IMPORTANT IMPORTANT IMPORTANT
If you have yall expression in your source, make sure you explicitly do
:- use_module(library(yall)). :- use_module(library(apply)).
and (to also compile maplist/2, maplist/3 etc. calls.):
:- use_module(library(apply_macros)).
Either put the above into source file (module or code) or run the corresponding goals on the toplevel:
?- use_module(library(yall)), use_module(library(apply)), use_module(library(apply_macros)).
If you don't do that, the program will run. However, yall expressions will not have been compiled and will be interpreted (i.e. the predicates from library(yall)
will be used). This results in extreme program slowdowns if you the expressions are encountered often because the these predicates perform term copying (loops calling these become literally 1000 times slower).
For some reason (I'm not sure why), if you forget the use_module
instructions, reconsulting the module or source will cause SWI-Prolog to properly compile the expressions that occur therein. If you wonder why code runs faster after reloading it, that may be the reason.
It seems best to put the above use_module
calls into your
$HOME/.config/swi-prolog/init.pl
If you want to be verify whether you code was compiled properly, use listing/1 to dump the code of the predicate that uses a yall
expression.
A slight fix for the text of "closure"
The term's name is the name of a predicate of arity K and the term's L arguments (where L could be 0) correspond to L leftmost arguments of said predicate. The remaining K-L arguments are left open and will be filled in by at metacall time. For example, a closure involving atom_concat/3 might be the term atom_concat(prefix)
. In order of increasing L, one would have increasingly more complete closures that could be passed to call/3, all giving the same result
Don't forget the bracy part
A question that often comes up is due to different behaviour in autoloading/late-compilation and non-autoloading/compilation:
If you forget to add the "bracy part" of a lambda expression in an environment that performs autoloading of library(yall) (i.e. the toplevel), things may work fine:
bracy(L) :- X=a, maplist({X}/[Y,Z]>>atom_concat(X,Y,Z), [1,2,3,4], L). nobracy(L) :- X=a, maplist([Y,Z]>>atom_concat(X,Y,Z), [1,2,3,4], L). % KINDA FAULTY
At the toplevel, add the above predicates with =[user].=
?- bracy(L). L = [a1, a2, a3, a4]. ?- nobracy(L). L = [a1, a2, a3, a4].
Both predicates work.
However, if you run them like this or from a file, explicitly loading library(yall) and library(apply) (which apparently triggers compilation)
?- use_module(library(apply)). true. ?- use_module(library(yall)). true. ?- [user]. |: bracy(L) :- X=a, maplist({X}/[Y,Z]>>atom_concat(X,Y,Z), [1,2,3,4], L). |: nobracy(L) :- X=a, maplist([Y,Z]>>atom_concat(X,Y,Z), [1,2,3,4], L). |: % user://1 compiled 0.01 sec, 5 clauses true.
... then the code is more picky and nobracy/1 isn’t working:
?- bracy(X). X = [a1, a2, a3, a4]. ?- nobracy(X). ERROR: Arguments are not sufficiently instantiated
Indeed, when you run nobracy/1 at the toplevel, by the time the lambda expression is interpreted, X is bound and thus no longer a variable (making the use of the {}/1 construct unnecessary).
On the other hand, when nobracy/1 is compiled, there's no information on X other than it's a variable when compiling the lambda expression. Any variable occurring in the lambda expression that's not find in a local lambda parameter must be declared using the {}/1 construct.
You can inspect the code with listing/1 to know more:
In the first case:
?- listing(nobracy). nobracy(D) :- A=a, maplist([B, C]>>atom_concat(A, B, C), [1, 2, 3, 4], D). true.
it still has to be translated, but in the second case:
?- listing(nobracy). nobracy(A) :- true, maplist('__aux_yall_c4da103176fa8ec13a605c05ca9dd921fc8acdbf', [1, 2, 3, 4], A). true. ?- listing('__aux_yall_c4da103176fa8ec13a605c05ca9dd921fc8acdbf'). '__aux_yall_c4da103176fa8ec13a605c05ca9dd921fc8acdbf'(A, B) :- atom_concat(_, A, B). true.
Evidently, this is not going to work because atom_concat/3 gets fed a fresh variable on first position.
Morale de l'histoire: Don't forget the bracy part!!
See also
Finally, there is the package
http://eu.swi-prolog.org/pack/file_details/lambda/prolog/lambda.pl
which is another approach at adding lambda expressions to Prolog.
It references
http://www.complang.tuwien.ac.at/ulrich/Prolog-inedit/ISO-Hiord
which is also good to peruse.