How to return a parameterized type instance?

I’m learning ELM and got confused by the following code:

type MyType aa
  = Foo
  | Bar aa

-- case1: compiled
hi : Int -> MyType aa
hi ss = Foo

-- case2: not compiled
hi : Int -> MyType aa
hi ss =
  case ss of
    0 -> Foo
    _ -> Bar ss

My question is:

Why does the case2 not work? After all, it does return an instance of type MyType aa which comply with the function signature hi : Int -> MyType aa, regarding the case1 compiled even without the branch Bar ss.

Type annotations can’t be too general. It’s a MyType Int; it can’t be passed to a function that requires something else like MyType Flont. MyType aa is only valid if aa can be any type, such as here:

hi : MyType aa
hi =
    Foo

The return type of hi should be MyType Int, since u are returning a specific type instead of a generic one.

The return type of hi should be MyType Int

Why is it should? I’m thinking the other way around: A function annotation is an (intentional) declaration to external world on what it’s input and output types, without any concern of its implementation at that moment. I’m going with the declaring-first-impimenting-later programming approach.

So by a declaration hi : Int -> MyType aa, I’m telling the world that my hi will return an instance of type MyType aa. That’s why my case1 worked as it did return an instance of MyType aa. I cannot understand why the case2 failed as it also return an instance of MyType aa. The differences of these two are their internal implementation which I think are not that important so long as they both comply with the annotation.

I belive my thinking is wrong somewhere, I need help to twist it around.

The type variables in type annotations (i.e. the aa in your type Int -> MyType aa) are implicitly all-quantified. This means that the implementation of a function Int -> MyType aa must be valid for all choices of aa at once. In other words, the type Int -> MyType aa promises to produce a value of MyType aa for any value of aa that the caller of the function wishes.

In case 1, your function is valid, because Foo can be a value of MyType aa regardless of what aa is. Your function hi in case 2 can’t do that: if ss is an Int, Bar ss has type MyType Int, but not MyType String.

3 Likes

You hit right at my pain point, thanks a lot!

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.