I want to implement SKI combinators in Prolog.
There are just 3 simple rules:
- (I x) = x
- ((K x) y) = x
- (S x y z) = (x z (y z))
I came up with the following code by using epilog:
term(s)
term(k)
term(i)
term(app(X,Y)) :- term(X) & term(Y)
proc(s, s)
proc(k, k)
proc(i, i)
proc(app(i,Y), Y1) :- proc(Y,Y1)
proc(app(app(k,Y),Z), Y1) :- proc(Y,Y1)
proc(app(app(app(s,P1),P2),P3), Y1) :- proc(app( app(P1,P3), app(P2, P3) ), Y1)
proc(app(X, Y), app(X1, Y1)) :- proc(X, X1) & proc(Y, Y1)
proc(X,X)
It works for some cases but has 2 issues:
It takes too much time to execute simple queries:
term(X) & proc(app(app(k, X), s), app(s,k))100004 unification(s)
It requires multiple queries to process some terms. For example:
((((S(K(SI)))K)S)K) -> (KS)
requires 2 runs:
proc(app(app(app(app(s,app(k,app(s,i))),k),s),k), X) ==> proc(app(app(app(app(s,app(k,app(s,i))),k),s),k), app(app(app(s,i),app(k,s)),k)) proc(app(app(app(s,i),app(k,s)),k), X) ==> proc(app(app(app(s,i),app(k,s)),k), app(k,s))
Can you please suggest how to optimize my implementation and make it work on complex combinators?
edit: The goal is to reduce combinators. I want to enumerate them (without duplicates) where the last one is in normal form (if it exists of course).
It can be implemented with iterative deepening like this:
The term can be inputted and outputted as a list of characters with
term//1. The grammar ruleterm//1can also generate unique terms.The goal is to be as lazy as possible when reducing a term thus
dif/2and the library reif is used inreduce_/2. The predicatereduce_/2does a single reduction. If any of the argument ofreduce_/2is ground then termination is guarantee (checked with cTI).To reduce a term,
reduce_/4can be used. The first argument specifies the depth, the last argument holds the list of terms. The predicatereduce_/4is pure and does not terminate.The predicate
reduce/3succeeds if there is a normal form. It is recommended to provide a maximum depth (e.g.Cs = "(((SI)I)((SI)(SI)))"):Test with
((((S(K(SI)))K)S)K):