Pure Prolog Scheme Quine

前端 未结 3 647
走了就别回头了
走了就别回头了 2021-01-21 06:15

There is this paper:

William E. Byrd, Eric Holk, Daniel P. Friedman, 2012
miniKanren, Live and Untagged
Quine Generation via Relational Interpret

3条回答
  •  清歌不尽
    2021-01-21 06:29

    Here is a solution that uses a little blocking programming style. Its not using when/2, rather only freeze/2. There is one predicate expr/2 which checks whether something is a proper expression without any closure in it:

    expr(X) :- freeze(X, expr2(X)).
    
    expr2([X|Y]) :-
       expr(X),
       expr(Y).
    expr2(quote).
    expr2([]).
    expr2(cons).
    expr2(lambda).
    expr2(symbol(_)).
    

    And then there is a lookup predicate again using freeze/2,
    to wait for an environment list.

    lookup(S, E, R) :- freeze(E, lookup2(S, E, R)).
    
    lookup2(S, [S-T|_], R) :-
       unify_with_occurs_check(T, R).
    lookup2(S, [T-_|E], R) :-
       dif(S, T),
       lookup(S, E, R).
    

    And finally the evaluator, which is coded using DCG,
    to limit the total number of cons and apply invokations:

    eval([quote,X], _, X) --> [].
    eval([], _, []) --> [].
    eval([cons,X,Y], E, [A|B]) -->
       step,
       eval(X, E, A),
       eval(Y, E, B).
    eval([lambda,symbol(X),B], E, closure(X,B,E)) --> [].
    eval([X,Y], E, R) -->
       step,
       eval(X, E, closure(Z,B,F)),
       eval(Y, E, A),
       eval(B, [Z-A|F], R).
    eval(symbol(S), E, R) -->
       {lookup(S, E, R)}.
    
    step, [C] --> [D], {D > 0, C is D-1}.
    

    The main predicate gradually increases the number of allowed
    cons and apply invokations:

    quine(Q, M, N) :-
       expr(Q),
       between(0, M, N),
       eval(Q, [], P, [N], _),
       unify_with_occurs_check(Q, P).
    

    This query shows that 5 cons and apply invokations are enough to produce a Quine. Works in SICStus Prolog and Jekejeke Prolog. For SWI-Prolog need to use for example this unify/2 workaround:

    ?- dif(Q, []), quine(Q, 6, N).
    Q = [[lambda, symbol(_Q), [cons, symbol(_Q), [cons, [cons, 
    [quote, quote], [cons, symbol(_Q), [quote, []]]], [quote, 
    []]]]], [quote, [lambda, symbol(_Q), [cons, symbol(_Q), [cons, 
    [cons, [quote, quote], [cons, symbol(_Q), [quote, []]]], 
    [quote, []]]]]]],
    N = 5 
    

    We can manually verify that it is indeed a non-trivial Quine:

    ?- Q = [[lambda, symbol(_Q), [cons, symbol(_Q), [cons, [cons, 
    [quote, quote], [cons, symbol(_Q), [quote, []]]], [quote, 
    []]]]], [quote, [lambda, symbol(_Q), [cons, symbol(_Q), [cons, 
    [cons, [quote, quote], [cons, symbol(_Q), [quote, []]]], 
    [quote, []]]]]]], eval(Q, [], P, [5], _).
    Q = [[lambda, symbol(_Q), [cons, symbol(_Q), [cons, [cons, 
    [quote, quote], [cons, symbol(_Q), [quote, []]]], [quote, 
    []]]]], [quote, [lambda, symbol(_Q), [cons, symbol(_Q), [cons, 
    [cons, [quote, quote], [cons, symbol(_Q), [quote, []]]], 
    [quote, []]]]]]],
    P = [[lambda, symbol(_Q), [cons, symbol(_Q), [cons, [cons, 
    [quote, quote], [cons, symbol(_Q), [quote, []]]], [quote, 
    []]]]], [quote, [lambda, symbol(_Q), [cons, symbol(_Q), [cons, 
    [cons, [quote, quote], [cons, symbol(_Q), [quote, []]]], 
    [quote, []]]]]]] 
    

提交回复
热议问题