定义“let 表达式"在序言中 [英] Defining "let expressions" in Prolog

查看:53
本文介绍了定义“let 表达式"在序言中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在许多函数式编程语言中,可以重新定义"使用 let 表达式的局部变量:

In many functional programming languages, it is possible to "redefine" local variables using a let expression:

let example = 
    let a = 1 in
        let a = a+1 in
            a + 1

为此我找不到内置的 Prolog 谓词,因此我尝试以这种方式定义 let 表达式:

I couldn't find a built-in Prolog predicate for this purpose, so I tried to define a let expression in this way:

:- initialization(main).
:- set_prolog_flag(double_quotes, chars).

replace(Subterm0, Subterm, Term0, Term) :-
        (   Term0 == Subterm0 -> Term = Subterm
        ;   var(Term0) -> Term = Term0
        ;   Term0 =.. [F|Args0],
            maplist(replace(Subterm0,Subterm), Args0, Args),
            Term =.. [F|Args]
        ).

let(A,B) :-
    ((D,D1) = (A1 is B1,C is B1);
    (D,D1) = (A1=B1,C=B1)),
    subsumes_term(D,A),
    D=A,
    replace(A1,C,B,B2),
    call((D1,B2)).

main :- let(A = 1,(
            writeln(A),
            let(A is A+1,(
                writeln(A),
                let(A is A * 2,(
                    writeln(A)
                ))
            ))
        )).

此实现似乎不正确,因为某些变量在替换之前已绑定.我想定义一个表达式,它允许重新定义"多个变量;同时:

This implementation appears to incorrect, since some of the variables are bound before being replaced. I want to define an expression that would allow more than one variable to be "redefined" simultaneously:

main :- let((A = 1, B = 2), % this will not work with the let/2 predicate that I defined
            let((A=B,B=A),(
                writeln(A),
                writeln(B)
            ))  
        ).

是否可以以允许同时重新定义多个变量的方式来实现 let 表达式?

Is it possible to implement a let expression in a way that allows several variables to be redefined at the same time?

推荐答案

let 定义为普通谓词的问题是您不能重新定义出现在最外层 let 之外的变量.这是我尝试使用目标扩展的更正确版本.(对我来说这是有道理的,因为据我所知,在类似 lisp 的语言中,let 不能定义为函数,但可以定义为宏.)

The issue with defining let as a normal predicate is that you can't redefine variables that appear outside the outermost let. Here is my attempt at a more correct version, which uses goal expansion. (To me it makes sense, because as far as I know, in lisp-like languages, let cannot be defined as a function but it could be defined as a macro.)

%goal_expansion(let(Decl,OriginalGoal),Goal) :- %% SWI syntax
goal_expansion(let(Decl,OriginalGoal), _M, _, Goal, []) :- %%SICStus syntax 
        !,
        expand_let(Decl,OriginalGoal,Goal).
        
expand_let(X, OriginalGoal, Goal) :-
        var(X),
        !,
        replace(X,_Y,OriginalGoal,NewGoal),
        Goal=(true,NewGoal).        
expand_let(X is Decl, OriginalGoal, Goal) :-
        var(X),
        !,
        replace(X,Y,OriginalGoal,NewGoal),
        Goal=(Y is Decl,NewGoal).
expand_let(X = Decl, OriginalGoal, Goal) :-
        var(X),
        !,
        replace(X,Y,OriginalGoal,NewGoal),
        Goal=(Y = Decl,NewGoal).
expand_let([],OriginalGoal, Goal) :-
        !,
        Goal=OriginalGoal.
expand_let([L|Ls],OriginalGoal, Goal) :-
        !,
        expand_let_list([L|Ls],OriginalGoal,InitGoals,NewGoal),
        Goal=(InitGoals,NewGoal).
expand_let((L,Ls),OriginalGoal, Goal) :-
        !,
        expand_let(Ls,OriginalGoal, SecondGoal),
        expand_let(L,SecondGoal, Goal).

expand_let_list([],Goal,true,Goal).
expand_let_list([L|Ls],OriginalGoal,(Init,InitGoals),NewGoal):-
        (
          var(L)
        ->
          replace(L,_,OriginalGoal,SecondGoal),
          Init=true
        ;
          L=(X=Decl)
        ->
          replace(X,Y,OriginalGoal,SecondGoal),
          Init=(Y=Decl)
        ;
          L=(X is Decl)
        ->
          replace(X,Y,OriginalGoal,SecondGoal),
          Init=(Y is Decl)
        ),
        expand_let_list(Ls,SecondGoal,InitGoals,NewGoal).

这是重用问题中定义的 replace/4 谓词.还要注意钩子谓词在 Prolog 版本之间是不同的.我正在使用 SICStus,它定义了 goal_expansion/5.我快速浏览了文档,似乎 SWI-Prolog 有一个 goal_expansion/2.

This is reusing the replace/4 predicate defined in the question. Note also that the hook predicate differs between Prolog versions. I am using SICStus, which defines goal_expansion/5. I had a quick look at the documentation and it seems that SWI-Prolog has a goal_expansion/2.

我为单个 let 中的多个声明引入了不同的语法:let((X1,X2),...) 定义了 X1,然后定义X2(所以等价于let(X1,let(X2,...))),而let([X1,X2],...) 同时定义了 X1X2(允许交换示例).

I introduced a different syntax for multiple declarations in a single let: let((X1,X2),...) defines X1, then defines X2 (so is equivalent to let(X1,let(X2,...))), while let([X1,X2],...) defines X1 and X2 at the same time (allowing the swap example).

以下是一些调用示例:

test1 :- let(A = 1,(
            print(A),nl,
            let(A is A+1,(
                print(A),nl,
                let(A is A + 1,(
                    print(A),nl
                ))
            ))
        )).

test2 :- A=2,let([A=B,B=A],(print(B),nl)).

test3 :- A=1, let((
                    A is A * 2,
                    A is A * 2,
                    A is A * 2
                  ),(
                      print(A),nl
                    )),print(A),nl.

test4 :- let([A=1,B=2],let([A=B,B=A],(print(A-B),nl))).

test5 :- let((
               [A=1,B=2],
               [A=B,B=A]
             ),(
                 print(A-B),nl
               )).

这篇关于定义“let 表达式"在序言中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆