Yall lambda arguments visibility

I’m coming from Lisp so I’m certainly biased.

Something that surprised me using lambdas is that arguments are visible from the outside of the lambda expression.

for instance:

?- maplist([X] >> (X #= 1),X).
X = [] ;
ERROR: Domain error: `clpfd_expression' expected, found `[_138018|_138020]'

fails because the outter X (which is a list) try to unify with the first argument of the lambda (I believe…)

with non colliding var names it behaves normally

?- maplist([X] >> (X #= 1),L).
L = [] ;
L = [1] ;
L = [1, 1] ;
L = [1, 1, 1] .
...

From a Lisp perspective it do not really makes sense, could anyone explain me why is this semantic is correct ?

Thank you a lot.

It is even more complicated :frowning: Suppose we write this:

:- use_module(library(clpfd)).
:- use_module(library(apply)).
:- use_module(library(yall)).

t(X) :-
    maplist([X] >> (X #= 1),X).

Now we get

?- t(X).
X = [] ;
X = [1] ;
X = [1, 1] ;
X = [1, 1, 1] .

This is because all predicates are known and the yall library will use goal expansion to generate a helper predicate which causes the variable sharing to disappear.

The dynamically called version doesn’t do this. I’m not sure whether or not it would be possible to make the behavior fully consistent.

The alternative is the add on lambda, which AFAIK always uses dynamic calling while I think it does examples like this correctly. The price is an even more ugly syntax and pretty high runtime overhead.

All in all, Lambdas seem to fit Prolog poorly. They have been discussed for decades. At some point library(lambda) and library(yall) got some popularity, notably for people with a functional programming background. I still prefer the solution below. Ok, it needs one more line. Often you can find a sensible name for the helper which makes your code more readable.

t(L) :- maplist(one, L).

one(X) :- X #= 1.
4 Likes

Thank you a lot for this detailed answer ! :slight_smile: