Date tor 27 september 2018

I see that swi prolog is landing a closure package. That's good. This led to me dusting off my closure implementation in guile-log which had bit-rotten somewhat and needed a retake. This is now the interface.

A closure can be created simplest with name{X,...Z|Goal} or for non arguments, name{|Goal} it will be directly inserted into the forms meaning that you can't currently manage these lambdas as code objects en e.g. macros. So an example would be

prolog> X is lam{X|X is 1},X(A).
--->
X = lam
A = 1

Note that we name the closure creation function lam and enter it in the name space which means that now this will be equivalent,

prolog> X is lam(), X(A).
--->
X = lam
A = 1

This is useful, but you might not want to name it in that case use lambda or λ and then a unique name will be generated. Anyway naming the lambdas can lead to interesting applications as a way to create closures generating functions. A problem in prolog is to close variables over, we depart here from swi prolog implementation in that closed over variables is marked like v[X]. This means that we can now design more useful lambdas. Here is a show case

prolog> var(Y),G is lam{X|X is v[Y]},Y is 1,G(A),set(Y,2),G(B).
–>
G = lam,
Y = 2.
A = 1,
B = 2.

Note here that all variables in is,<,>,... is has an implicit lookup which is why this works. If you used X = Y in stead we would get A=2 in stead.

A closure can create closures which can create closures. This works

prolog> var(Y),F=lam{S,G|S is s{X|set(v[Y],X)},
                         G is g{X|X is v[Y]  }},
        F(S,G),S(1),G(A),S(2),G(B).
–>
F = lam
S = s
G = g
A = 1
B = 2
Y = 2

Now if anywhere in the chain of closures a Y is bound that will take precedence and therefore we could have introduced Y in the first closure like,

prolog> F=lam{S,G|var(Y),S is s{X|set(v[Y],X)},
                         G is g{X|X is v[Y]  }},
        F(S,G),S(1),G(A),S(2),G(B).
–>
F = lam
S = s
G = g
A = 1
B = 2

Note also that we can use the named closure creators and the below is now equivalent

prolog> S is s(Y), G is g(Y),S(1),G(A),S(2),G(B).
–>
S = s,
G = g,
A = 1,
B = 2,
Y = 2.

Another thing that departs from swi prologs closures is that we have another form that is quite general and we call it a letrec form. the prototype is lam{LHS1 :- RHS1. ... LHS10 :- RHS10.} the predicate shoosen as a closure is also named lam or in case we use annynomous prefix the last predicate inside the bracket. So with this we can do

prolog> Y=1,X is lam{
           f(X) :- X = v[Y].

           lam([]).
           lam([X|L]) :-
              f(X),
              lam(L).},

        length(A,3),X(A).
–>
Y = 1
X = lam
A = [1,1,1]

Which get's a little more interesting when we can do this after evaluating the above,

prolog> X is lam(1), Y is lam(2), Z is lam(_), Y=Z,
        length(A,3),X(A),
        length(B,3),Y(B),
        length(C,3),Z(C).
–>
X = lam,
Y = lam,
Z = lam,
A = [1,1,1],
B = [2,2,2],
C = [2,2,2].

Note how we unified two closures. to se more output of the lambdas, please write the term with quoted(true).

prolog> Y=1,X is {X|X is Y},write_term(X,[quoted(true)]),nl.
"A1=lam(1)"

X = lam,
Y = 1.

Happy hacking!!


Comments

comments powered by Disqus

~ Follow me ~