[mercury-users] typeclass error

Ian MacLarty maclarty at cs.mu.OZ.AU
Thu Jan 19 23:09:03 AEDT 2006


On 19 Jan 2006, at 14:00, Mark Brown wrote:

> On 19-Jan-2006, Ian MacLarty <maclarty at cs.mu.OZ.AU> wrote:
>> On 19 Jan 2006, at 05:39, Mark Brown wrote:
>>
>>> On 18-Jan-2006, Ian MacLarty <maclarty at cs.mu.OZ.AU> wrote:
>>>> Hello,
>>>>
>>>> What's wrong with the following program?
>>>>
>>>> :- module tc.
>>>>
>>>> :- interface.
>>>>
>>>> :- import_module io.
>>>>
>>>> :- pred main(io::di, io::uo) is det.
>>>>
>>>> :- implementation.
>>>>
>>>> :- import_module list, int.
>>>>
>>>> main(!IO) :-
>>>>        nl(!IO).
>>>>
>>>> :- typeclass tc1(A, C) where [
>>>>        func a_to_c(A) = C
>>>> ].
>>>>
>>>> :- typeclass tc2(B, C) where [
>>>>        func b_to_c(B) = C
>>>> ].
>>>>
>>>> :- func f(A, B) = C <= (tc1(A, C), tc2(B, C)).
>>>>
>>>> f(A, B) =
>>>>        ( if a_to_c(A) = b_to_c(B) then
>>>>                a_to_c(A)
>>>>        else
>>>>                b_to_c(B)
>>>>        ).
>>>
>>> First, here's the clause with some explicit type annotations:
>>>
>>> 	f(A, B):C0 =
>>> 		( if a_to_c(A):C1 = b_to_c(B):C2 then
>>> 			a_to_c(A):C3
>>> 		else
>>> 			b_to_c(A):C4
>>> 		):C5.
>>>
>>> Because of the result unification, we know that C0 = C5.  Because of
>>> the
>>> semantics of if-then-else expressions, we know that C3 = C5 and C4 =
>>> C5.
>>> Because of the unification in the condition, we know that C1 = C2.  
>>> So
>>> at
>>> this stage there are two equivalence classes: {C0,C3,C4,C5} and
>>> {C1,C2}.
>>> There is nothing in the clause which implies that these two 
>>> equivalence
>>> classes are the same.
>>>
>>> The first equivalence class is the type of the function result, so it
>>> is
>>> bound to the universally quantified C from the func declaration.  
>>> Hence
>>> the method calls in the "then" and "else" branches will call methods 
>>> in
>>> those dictionaries that are passed in as hidden arguments to f (that
>>> is,
>>> the dictionaries that correspond to the two constraints on the func
>>> declaration).
>>>
>>> The second equivalence class remains unbound.  Hence there are no
>>> assumed
>>> constraints (e.g., constraints on the func declaration) that can
>>> satisfy
>>> the constraints on the method calls in the condition; this explains 
>>> the
>>> first part of the error message.  The warning you get is because
>>> unbound
>>> type variables are generally never what the programmer intends.
>>>
>>
>> That all makes perfect sense.  I was under the illusion that the
>> compiler would know that C1 and C3 are of the same type, because they
>> have the same value, but I guess type inference doesn't know anything
>> about the values.
>
> Without the functional dependency, they wouldn't necessarily have the 
> same
> value, let alone the same type.  ;-)
>
> Consider:
>
> 	:- typeclass convertible(A, B) where [
> 		func cast(A) = B
> 	].
>
> 	:- instance convertible(int, int) where [
> 		(cast(N) = N)
> 	].
>
> 	:- instance convertible(int, string) where [
> 		(cast(_) = "some number")
> 	].
>
> 	main(!IO) :-
> 		io.write_string(cast(1), !IO),
> 		io.nl(!IO),
> 		io.write_int(cast(1), !IO),
> 		io.nl(!IO).
>
> The output would be:
>
> 	some number
> 	1
>
> You should think of cast/1 as being an overloaded name, which is why it
> appears to violate referential transparency.
>

Good point.

Ian.

--------------------------------------------------------------------------
mercury-users mailing list
post:  mercury-users at cs.mu.oz.au
administrative address: owner-mercury-users at cs.mu.oz.au
unsubscribe: Address: mercury-users-request at cs.mu.oz.au Message: unsubscribe
subscribe:   Address: mercury-users-request at cs.mu.oz.au Message: subscribe
--------------------------------------------------------------------------



More information about the users mailing list