[Haskell] Polimorfismo sopra e sotto il where

kaspar1
Ciao :smt039

Non so come esprimere bene il problema per poi magari cercare una soluzione da me. Quindi faccio un esempio:

import Control.Conditional
import System.IO

-- In realtà non è importante sapere cosa fanno le funzioni...
slurp :: (String -> a) -> FilePath -> IO [a]
slurp f fp = withFile fp ReadMode helper
  where
    helper :: Handle -> IO [a]
    helper hdl = ifM (hIsEOF hdl) (return []) $ do
        ln <- hGetLine hdl
        fmap (f ln :) (helper hdl)


L'errore che il compilatore mi mostra è questo:

[...] error:
    • Couldn't match type ‘a1’ with ‘a’
      ‘a1’ is a rigid type variable bound by
        the type signature for:
          helper :: forall a1. Handle -> IO [a1]
        at sand.hs:30:5-30
      ‘a’ is a rigid type variable bound by
        the type signature for:
          slurp :: forall a. (String -> a) -> FilePath -> IO [a]
        at sand.hs:27:1-44
      Expected type: IO [a1]
        Actual type: IO [a]
[...]


Mi ha distinto le due [tt]a[/tt] in pratica. Come faccio a dire al compilatore "per [tt]helper[/tt] voglio proprio quella [tt]a[/tt] del tipo di [tt]slurp[/tt]"?

Risposte
apatriarca
Dai una occhiata a questa pagina di stackoverflow. In generale le soluzioni dovrebbero essere (non ho accesso in questo momento ad un compilatore per Haskell per cui non posso provare):
{-# LANGUAGE ScopedTypeVariables #-}
slurp :: forall a. (String -> a) -> FilePath -> IO [a]
slurp f fp = withFile fp ReadMode helper
  where
    helper :: Handle -> IO [a]
    helper hdl = ifM (hIsEOF hdl) (return []) $ do
        ln <- hGetLine hdl
        fmap (f ln :) (helper hdl)

slurp :: (String -> a) -> FilePath -> IO [a]
slurp f fp = withFile fp ReadMode $ helper f
  where
    helper :: (String -> a) -> Handle -> IO [a]
    helper f hdl = ifM (hIsEOF hdl) (return []) $ do
        ln <- hGetLine hdl
        fmap (f ln :) (helper hdl)


Un'altra soluzione è quella di non scrivere la type signature della funzione interna in quanto Haskell dovrebbe essere in quel caso in grado di inserire il tipo corretto da solo.

kaspar1
Perfetto, funziona.

"apatriarca":

Un'altra soluzione è quella di non scrivere la type signature della funzione interna in quanto Haskell dovrebbe essere in quel caso in grado di inserire il tipo corretto da solo.


Certo. esistono anche altri modi[nota]La più ovvia:
import Control.Conditional
import System.IO

slurp :: (String -> a) -> FilePath -> IO [a]
slurp f fp = withFile fp ReadMode (hSlurp f)

hSlurp :: (String -> a) -> Handle -> IO [a]
hSlurp f hdl =
    ifM (hIsEOF hdl) (return []) $ do
        ln <- hGetLine hdl
        fmap (f ln :) (hSlurp f hdl)
[/nota]. Ma volevo sapere come fare precisamente questa cosa.

Rispondi
Per rispondere a questa discussione devi prima effettuare il login.