Adding a signature type to where the statement causes the error, I don't understand

I am working on a complex function in yesod. It has many functions in that part which is untyped, but typecheck is correct. I decided to try adding a few type signatures so that I can figure out what happens one piece at a time, but adding type signatures caused type errors.

So, I reduced this function to a simple case, to post a message here that still gives a similar error, which I don't understand.

helper :: [(String, a)] -> [(Int, a)] helper xs = blah where blah :: [(Int, a)] blah = zip [1..10] (map snd xs) 

If I remove the type signature from the blah, it compiles just fine, but if I add this type signature, it will give me an error:

 Couldn't match type `a' with `a1' `a' is a rigid type variable bound by the type signature for helper :: [(String, a)] -> [(Int, a)] at Blah.hs:4:1 `a1' is a rigid type variable bound by the type signature for blah :: [(Int, a1)] at Blah.hs:7:5 Expected type: [(String, a1)] Actual type: [(String, a)] In the second argument of `map', namely `xs' In the second argument of `zip', namely `(map snd xs)' 
  • I also do not know why the "a" in the helper is interpreted as a different "a" than the helper when type checking occurs.
  • Why does it even bother if a differs in the first place
  • I have no idea how to determine what type of drone is actually because I cannot move it to the upper level, still using its argument.

Edit:

Ok, I have one more edit before I mention this. There are some limitations in the code I use (Eq a, Monad monad) => etc, etc. Etc., And so the solution that I have does not quite work. Therefore, I modify my sample code to be closer to the real code:

 helper :: (Eq a, Num b) => b -> [(String, a)] -> (b, [(Int, a)]) helper b xs = (b+b, blah) where blah :: [(Int, a)] blah = filter (\y -> fst y == 11) $ zip [1..10] (map snd xs) 

If i put

 helper :: forall a. (Eq a, Num b) => b -> [(String, a)] -> (b, [(Int, a)]) 

this does not work because (I assume that b is not in scope, but I cannot understand the syntax to get forall b in this type. (forall a, forall b does not work, forall a, b does not work).

+4
source share
1 answer

a a does not match type a in type helper unless you use the ScopedTypeVariables extension. So, your type signatures say they are independent, but they are clearly not. Your code is equivalent to this:

 helper :: forall a. [(String, a)] -> [(Int, a)] helper xs = blah where blah :: forall b. [(Int, b)] blah = zip [1..10] (map snd xs) 

Here you say that for any given a we can choose any b , but it is not. Since xs is of type [(String, a)] , map snd xs is of type [a] . Thus, a and b must be of the same type, i.e. a ~ b . So the compiler complains that blah not as polymorphic as you said it was in a type signature.

You have three options:

  • Remove the type signature. The compiler will infer the correct type for blah .

  • Enable ScopedTypeVariables . Then the compiler realized that you want a in type blah to be the same as a in signature helper . In this case, you need to add explicit forall a. in a signature like helper :

     {-# LANGUAGE ScopedTypeVariables #-} helper :: forall a. [(String, a)] -> [(Int, a)] helper xs = blah where blah :: [(Int, a)] blah = zip [1..10] (map snd xs) 
  • Make blah type independent:

     helper :: [(String, a)] -> [(Int, a)] helper xs = blah xs where blah :: [(String, b)] -> [(Int, b)] -- Or 'a'. Doesn't matter. blah ys = zip [1..10] (map snd ys) 

    Now blah will work on any b . The fact that you only use it with b ~ a is great.

Reply to edit:

Use a space between type variables in forall , e.g.

 helper :: forall a b. (Eq a, Num b) => ... 
+13
source

All Articles