At yall.pl – Lambda expressions, we read:
The
{...}
optional part is used for lambda-free variables. The order of variables doesn’t matter hence the{...}
set notation.
The “bracy part” is indeed “optional” in that it seems to have no effect at all, at least in the context of maplist/N
(see tests c2
and c3
below). It really should be mandatory (IMHO etc, hopefully in a future version).
But is there anyplace currently where it is NOT optional? Maybe in Logtalk?
:- begin_tests(maplist_and_yall).
% ---
% Calling maplist/4 with an atomic goal and an equivalent
% Lambda-Expression
% (i.e. a "predicate shim") suing library(yall).
% Everything is as expected.
% ---
test(a1, true(L = [a1, b2, c3, d4])) :-
maplist(atom_concat, [a,b,c,d], [1,2,3,4], L).
test(a2, true(L = [a1, b2, c3, d4])) :-
maplist([X,Y,Z]>>atom_concat(X,Y,Z), [a,b,c,d], [1,2,3,4], L).
% ---
% Calling maplist/3 with a "Prolog closure" (i.e. an atomic goal with
% leftmost arguments instantiated).
% Alternatively, calling maplist/3 with a dedicated helper predicate.
% Everything is as expected. But as usual, Richard III applies: "A
% clause-local namespace accepting predicates, my kingdom for a
% clause-local namespace accepting predicates ... that I
% can just cut & paste at the toplevel without having to go [user].!".
% "No, sir!"
% ---
test(b1, true(L = [a1, a2, a3, a4])) :-
maplist(atom_concat(a), [1,2,3,4], L).
b2_helper(X,Y) :- atom_concat(a,X,Y).
test(b2, true(L = [a1, a2, a3, a4])) :-
maplist(atom_concat(a), [1,2,3,4], L).
% ---
% Alternatively, calling maplist/3 with and Lambda-Expressions from
% library(yall):
%
% The point of the exercise is here: c2 and c3 work the same, the "{X}"
% notation which is supposed to "grab a variable from the enclosing
% context" has no effect, really.
% ---
test(c1, true(L = [a1, a2, a3, a4])) :-
maplist([Y,Z]>>atom_concat(a,Y,Z), [1,2,3,4], L).
test(c2, true(L = [a1, a2, a3, a4])) :-
X=a, maplist([Y,Z]>>atom_concat(X,Y,Z), [1,2,3,4], L).
test(c3, true(L = [a1, a2, a3, a4])) :-
X=a, maplist({X}/[Y,Z]>>atom_concat(X,Y,Z), [1,2,3,4], L).
% ---
% Alternatively, an example accepting fresh variables (a leftover in my
% test code, just adding it)
% ---
freshy(X,fresh) :- var(X),!.
freshy(X,cured(X)) :- nonvar(X).
test(d1, true(L = ["fresh 1", "fresh 2", "fresh 3", "fresh 4"])) :-
maplist([Y,Z]>>(freshy(_X,Xf),with_output_to(string(Z),format("~q ~q",[Xf,Y]))), [1,2,3,4], L).
test(d2, true(L = ["cured(a) 1", "cured(a) 2", "cured(a) 3", "cured(a) 4"])) :-
X=a, maplist([Y,Z]>>(freshy(X,Xf),with_output_to(string(Z),format("~q ~q",[Xf,Y]))), [1,2,3,4], L).
:- end_tests(maplist_and_yall).
rt :- run_tests(maplist_and_yall).