[mercury-users] Can this be done better?

Richard O'Keefe ok at cs.otago.ac.nz
Tue Jan 31 12:35:21 AEDT 2012

On 31/01/2012, at 12:55 AM, Michael Richter wrote:

> Issue #1
> main(!IO) :-
>    Forward = [math.sin, math.cos, (func(X) = math.ln(X))],
>    Reverse = [math.asin, math.acos, (func(X) = math.exp(X))],
>    apply(list.zip(Forward, Reverse), [], Results),
>    io.write_list(Results, ", ", io.write_float, !IO),
>    io.write_string("\n", !IO).
> :- pred apply(list((func(float) = float)), list(float), list(float)).
> :- mode apply(in, in, out) is det.
> apply([], A, Results) :- Results = A.
> apply([F, R|Functions], A, Results) :-
>    apply(Functions, [compose(R, F, 0.5) | A], Results).
> apply([_], _, _) :- throw("This can't happen!").
> The problem is that apply/3 without that third clause is deemed semidet because the second clause's head "can fail" (in that R may not always be bound according to the compiler).  Of course this is nonsense in this given situation because the list being passed in will always come in pairs, but naturally the compiler can't know that.  For me to get this code to compile I have to add that third clause (which will never be evaluated) just because.

Does anyone else find it confusing that list.zip does an "interleave"
(alternating elements) rather than a "zip" (pair of lists -> list of

If we look at the code,

    list__zip([], Bs, Bs). 
    list__zip([A | As], Bs, [A | Cs]) :-
        list__zip2(As, Bs, Cs).

    list__zip2(As, [], As).
    list__zip2(As, [B | Bs], [B | Cs]) :-
        list__zip(As, Bs, Cs).

we see that list.zip can in general deliver both even-length AND
odd-length results.

What you want is to roll your own 'zip' that has a more conventional

:- pred myzip(list(T1), list(T2), list(pair(T1,T2)).
---- add your own mode declarations ----
myzip([X|Xs], [Y|Ys], [pair(X,Y)|Pairs]).
myzip([],     [],     []).

:- pred apply(list(pair(func(float) = float, func(float) = float)), list(float), list(float)).
:- mode apply(in, in, out) is det.
apply([],               Ans,  Ans). 
apply([pair(F,G)|Funs], Ans0, Ans) :-
    apply(Funs, [compose(G, F, 0.5) | Ans0], Ans).

There are alternatives, like defining your own alternating-list type:

:- type alist(T1,T2)
   ---> nil
      ; cons(T1,T2,alist(T1,T2)).

(this is basically just an unfolding of list(pair(T1,T2)).)

mercury-users mailing list
Post messages to:       mercury-users at csse.unimelb.edu.au
Administrative Queries: owner-mercury-users at csse.unimelb.edu.au
Subscriptions:          mercury-users-request at csse.unimelb.edu.au

More information about the users mailing list