Is there something like anonymous predicates in SWI Prolog?
Asked Answered
S

3

5

Can I define an anonymous predicate in SWI Prolog, bind it to a variable, and call it later? Something like this:

?- F = {(X, Y) :- Y is 2 * X}, call(F, 2.0, Y).
Semite answered 19/6, 2019 at 7:17 Comment(1)
You don't need to write (X,Y), you can simply write X,Y since the term is inside '{}'/1, and according to ISO core standard the argument to '{}'/1 starts with operator level 1200.Teenybopper
K
7

Alternatively, in SWI-Prolog, you can use library(yall). It can be autoloaded so you don't need to import anything:

?- F = [X, Y]>>( Y is 2*X ), call(F, 2.0, Y).
F = [X, 4.0]>>(4.0 is 2*X),
Y = 4.0.

I think that in the general case it would be better to use a new variable for the result of calling the lambda:

?- F = [X, Y]>>( Y is 2*X ), call(F, 2.0, R).
F = [X, Y]>>(Y is 2*X),
R = 4.0.
Kale answered 19/6, 2019 at 11:32 Comment(0)
M
8

That´s what lambdas are for:

?- use_module(library(lambda)).
   true.
?- F_2 = (\X^Y^ ( Y is 2*X )), call(F_2,2.0,Y).
   F_2 = \X^4.0^(4.0 is 2*X), Y = 4.0.
Meteoritics answered 19/6, 2019 at 8:46 Comment(2)
Great! Just a small addition: lambda is a community package that can be installed via ?- pack_install('http://www.swi-prolog.org/download/pack/lambda-*.tgz').Semite
Your library is also available as a dual package now: Ulrich Neumerkels library(lambda) ready for airdropTeenybopper
K
7

Alternatively, in SWI-Prolog, you can use library(yall). It can be autoloaded so you don't need to import anything:

?- F = [X, Y]>>( Y is 2*X ), call(F, 2.0, Y).
F = [X, 4.0]>>(4.0 is 2*X),
Y = 4.0.

I think that in the general case it would be better to use a new variable for the result of calling the lambda:

?- F = [X, Y]>>( Y is 2*X ), call(F, 2.0, R).
F = [X, Y]>>(Y is 2*X),
R = 4.0.
Kale answered 19/6, 2019 at 11:32 Comment(0)
T
5

So far no modern lambda libraries support the Hiord syntax, not to be confused with the Hilog syntax. But since in ISO Prolog curly braces are just the functor '{}'/1, one can do his own Hiord with a few rules:

'{}'((Formal :- Body), Actual) :-
   copy_term(Formal-Body, Actual-Call),
   Call.
'{}'((Formal1,Formal2 :- Body), Actual1, Actual2) :-
   copy_term(Formal1-Formal2-Body, Actual1-Actual2-Call),
   Call.
'{}'((Formal1,Formal2,Formal3 :- Body), Actual1, Actual2, Actual3) :-
   copy_term(Formal1-Formal2-Formal3-Body, Actual1-Actual2-Actual3-Call),
   Call.
 Etc..

Here are some example runs:

Jekejeke Prolog 3, Runtime Library 1.3.8 (May 23, 2019)
(c) 1985-2019, XLOG Technologies GmbH, Switzerland

?- F = {X :- write(X), nl}, call(F, hello).
hello

?- F = {X,Y :- Y is X+1}, call(F, 1, R).
R = 2

?- F = {X,Y,Z :- Z is X+Y}, call(F, 1, 2, R).
R = 3

When working with lambda terms, you will see that there are many issues. For example there is the question of global variables which has different solutions.

Besides that you might be also interested in lambda terms that allow currying. Hiord terms do not allow currying with the above implementation, for example this here fails:

?- G = {Y :- Y is X+1},  F = {X :- G}, call(F, 1, R).
Error: Undefined or inaccesible predicate {}/1.
    {}/1
    {}/3   

You would have more luck with Jekejeke Prologs library(experiment/abstract) which can also do currying:

?- G = Y\(Y is X+1), F = X\G, call(F, 1, R).
R = 2

SWI-Prologs lambda library can also do currying:

?- G = [Y]>>(Y is X+1), F = [X]>>G, call(F, 1, R).
R = 2.

And Ulrich Neumerkels library can also do currying:

?- G = \Y^(Y is X+1), F = \X^G, call(F, 1, R).
R = 2
Teenybopper answered 19/6, 2019 at 18:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.