Search code examples
haskellpolymorphismtypeerror

Haskell unexpected `forall` in typechecking failure


I am working on a mathematics project with a persistent need of extracting a canonical "basis" out of a type, so I defined the following type class.

class Basis a where
    getBasis :: Int -> [a]

And I want to use this basis in a separate function:

foo :: (Basis a) => Int -> (a -> b) -> IO ()
foo n f = do
    let theBasis = getBasis n
    undefined
    -- Do some stuff with the basis using the function f.
    -- theBasis should have type [a].

However this fails to type check, yielding an error of the form Could not deduce (Basis a0) arising from the use of 'getBasis' from the context: Basis a.

I tried to help the typechecker by explicitly writing the expected type:

foo n f = do
    let theBasis = (getBasis n) :: [a]
    undefined

But the error persists, and moving the type annotation to different terms in that line does not fix the error.

How can I tell the typechecker that I want the type of getBasis n to be the same a appearing in the signature of foo?


Solution

  • The easiest way to do this in this case would be to just use the basis for something, because then the typechecker can infer which a you meant:

    Silly example:

    foo :: Basis a => Int -> (a -> b) -> IO ()
    foo n f = do
        let theBasis = getBasis n
            _        = map f theBasis
        undefined
    

    Otherwise you can also use type annotations (requires the ScopedTypeVariables extension, without that the a inside the function body won't be the a from the signature):

    foo :: forall a b. Basis a => Int -> (a -> b) -> IO ()
    foo n f = do
        let theBasis = getBasis n :: [a]
        undefined
    

    With ScopedTypeVariables + TypeApplications you can also explicitly pass the type parameter a along to getBasis:

    foo :: forall a b. Basis a => Int -> (a -> b) -> IO ()
    foo n f = do
        let theBasis = getBasis @a n
        undefined