[clean-list] a local function typing question in function
composition
Philip Matthews
philip_matthews at magma.ca
Thu Apr 12 17:33:31 MEST 2007
Edsko:
Thanks for the long message.
See my detailed comment inline.
- Philip
On 12-Apr-07, at 10:54 , Edsko de Vries wrote:
> Hi Philip,
>
>> So, going back to the original example
>> f :: a -> a
>> f x = y
>> where
>> y :: a
>> y = x
>>
>> Start = f 5
>>
>> Here the error really is that the compiler cannot unify the type of
>> "y" in the expression "f x = y" with the type of "y" from the type
>> declaration "y :: a", because the "a"s are actually different type
>> variables. They are different type variables, but they need to be the
>> same in order to type check the function.
>>
>> Am I correct?
>
> No, not quite, but close :-) Let me illustrate with a slightly
> modified
> example:
>
> module t
>
> undefined :: z
> undefined = undefined
>
> f :: a -> a
> f x = y
> where
> y :: a
> y = undefined
>
> Start = f 5
>
> I'm declaring a term "undefined", which is simply defined to be
> itself. The
> point is that "undefined" has every type. That's what the type
> annotation says
> for undefined: the type of undefined is "z" *for every z*.
>
> This definition of f (which is identical to the previous, except
> that I defined
> y to be "undefined" rather than "x") is accepted by the compiler. Why?
>
> The annotation of "y" says that y has type a *for every a*. It checks
> the definition of y, and finds that it is defined to be
> "undefined"; it
> looks up the type of undefined, finds that undefined has type x *for
> every x* and thus accepts the type annotation.
>
> Then when it checks the body of f ("y"), it must check that y has
> type "a",
> where "a" is the type of the argument passed in (x). This is indeed
> a different
> a, BUT "y" has type "a" *for every a*, so that doesn't matter!
This is the part that I do not understand. "y" has type "a, for every
a" but it seems
to me that this type is too general. I would have thought that "y"
needs to have
the exact same type as "x".
Indeed, if you look at the program as a whole, it doesn't make sense,
because "undefined"
could return anything, and thus the actual value that "y" gets could
be anything.
I would argue that this example actually shows up a problem in the
Clean type system,
because the caller of "f" wants a value back which is of the same
type as the value passed in.
The only reason this "works" (and here I am using "works" very very
loosely) is that
the function "f" never terminates when called, so it is impossible to
actually inspect
the returned value. If "f" actually returned a value, then this would
clearly be a bug.
Never-the-less, from a practical prospective, I have learned the
following:
The type variables used in inner type declarations are ALWAYS
different
from the type variables in outer type declarations.
If I remember this rule, I think I can understand and avoid typing
errors.
It would be helpful if the error message
Type error [t.icl,6,y]:type variable of type of lifted argument a
appears in the specified type
could be changed to be a little bit more comprehensible. Before this
conversation,
I had no idea what this message meant, and even now I can only
vaguely interpret it.
> We could just as well have written:
>
> f :: a -> a
> f x = y
> where
> y :: b
> y = undefined
>
> and nothing would change. Now when we go back to the original example,
>
> f :: a -> a
> f x = y
> where
> y :: a
> y = x
>
> the type error is *not* in the body of, but in the body of y. The
> body of y
> says that y must have type a *for every a*, but in fact, y only has
> one type,
> that is, the type of the argument passed in (x). Unfortunately,
> since Clean
> doesn't have scoped type variables, we cannot write that down, but
> internally
> the typechecker will have assigned a type variable "T" to
> correspond to the
> type of x. Because y is defined to be x, Y will also have type "T".
> The type
> annotation of "y" says that y has every type you want it to have,
> but that's
> not the case (it has type T, and only type T).
>
> Again, this program is *exactly* the same program as
>
> f :: a -> a
> f x = y
> where
> y :: b
> y = x
>
> which is rejected for the same reason (now y has type b *for every
> b*, but that
> is of course the same type as type a *for every a* -- although
> perhaps it is
> easier to see that this program is wrong).
>
> Does that help?
>
> Edsko
More information about the clean-list
mailing list