Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Confused about Haskell polymorphic types

Tags:

haskell

I have defined a function :

gen :: a -> b

So just trying to provide a simple implementation :

gen 2 = "test"

But throws error :

gen.hs:51:9:
    Couldn't match expected type ‘b’ with actual type ‘[Char]’
      ‘b’ is a rigid type variable bound by
          the type signature for gen :: a -> b at gen.hs:50:8
    Relevant bindings include gen :: a -> b (bound at gen.hs:51:1)
    In the expression: "test"
    In an equation for ‘gen’: gen 2 = "test"
Failed, modules loaded: none.

So my function is not correct. Why is a not typed as Int and b not typed as String ?

like image 860
blue-sky Avatar asked Nov 30 '22 10:11

blue-sky


1 Answers

This is a very common misunderstanding.

The key thing to understand is that if you have a variable in your type signature, then the caller gets to decide what type that is, not you!

So you cannot say "this function returns type x" and then just return a String; your function actually has to be able to return any possible type that the caller may ask for. If I ask your function to return an Int, it has to return an Int. If I ask it to return a Bool, it has to return a Bool.

Your function claims to be able to return any possible type, but actually it only ever returns String. So it doesn't do what the type signature claims it does. Hence, a compile-time error.

A lot of people apparently misunderstand this. In (say) Java, you can say "this function returns Object", and then your function can return anything it wants. So the function decides what type it returns. In Haskell, the caller gets to decide what type is returned, not the function.

Edit: Note that the type you're written, a -> b, is impossible. No function can ever have this type. There's no way a function can construct a value of type b out of thin air. The only way this can work is if some of the inputs also involve type b, or if b belongs to some kind of typeclass which allows value construction.

For example:

head :: [x] -> x

The return type here is x ("any possible type"), but the input type also mentions x, so this function is possible; you just have to return one of the values that was in the original list.

Similarly, gen :: a -> a is a perfectly valid function. But the only thing it can do is return it's input unchanged (i.e., what the id function does).

This property of type signatures telling you what a function does is a very useful and powerful property of Haskell.

like image 110
MathematicalOrchid Avatar answered Dec 12 '22 16:12

MathematicalOrchid