Data structures prolog中的后缀到前缀的转换,一元运算符为sin-cos-tan等

Data structures prolog中的后缀到前缀的转换,一元运算符为sin-cos-tan等,data-structures,prolog,stack,logic,Data Structures,Prolog,Stack,Logic,我不熟悉Prolog。我正在努力学习这一点。我正在构建一个后缀到前缀的转换谓词。我搜索了很多google和github等。prolog递归语法非常混乱。通过寻找很多,我只是。我正在处理同一个问题,但指定的解决方案非常混乱。append/2函数的实现在我的脑海中并没有出现,单值运算符又如何呢?现在已经三天多了,我一直在解决这个问题,只是被吸了。任何人请帮助我实现这个逻辑或任何书籍参考或一些链接,以更好地了解相同的问题。谢谢 我想用这种方法解决它 post2pre([A,B,C|Rem],P

我不熟悉Prolog。我正在努力学习这一点。我正在构建一个后缀到前缀的转换谓词。我搜索了很多google和github等。prolog递归语法非常混乱。通过寻找很多,我只是。我正在处理同一个问题,但指定的解决方案非常混乱。append/2函数的实现在我的脑海中并没有出现,单值运算符又如何呢?现在已经三天多了,我一直在解决这个问题,只是被吸了。任何人请帮助我实现这个逻辑或任何书籍参考或一些链接,以更好地了解相同的问题。谢谢

我想用这种方法解决它

    post2pre([A,B,C|Rem],Pre) :- Pre=[C,A,B], isop(C).
但问题是如何处理Rem?如果列表中只有一两项呢 我想这样解决它

   post2pre([A|[]],Pre) :- Pre=[A].
   post2pre([A,B|[]) :- Pre=[A,B]. 
对于isOp(),我将它们定义为

   isop(+). isop(-). isop(*). isop(/). isop(sin). isop(cos). isop(exp).

但我不知道如何处理单值运算符?

好吧,正如我在回答中所建议的,pos2pre/2它只是一个草图,由学生完成。但这也是一个棘手的解决方案,我认为这是一个声明性的解决方案。因此,它可以很容易地扩展到处理一元运算符(我将isop/1重命名为is_binary_op/1,以清理代码):

试验

我尝试遵循的另一种方法是使用完全不同的方案,构建中缀表达式解析器(DCG),然后让树的后缀/前缀访问在格式之间转换

编辑这里是从SWI Prolog库中窃取的append/2谓词(列表):


这个!符号名为cut,它不是一个运算符,而是一个系统谓词(更准确地说,是一个控制谓词)。它总是成功的,并删减可能在执行点挂起的备选方案,从而承诺到目前为止所做的选择。你应该在网上阅读一些关于这个主题的文章…

这里有一个替代版本。这一个首先从后缀列表构建前缀结构,作为2或3元素列表的嵌套列表结构(每一个一元或二元操作),然后在末尾展平嵌套列表:

post2pre(Post, Pre) :-
    post2pre(Post, [], Pre).

post2pre([E|T], PreNest, Pre) :-
    (   unary_op(E)
    ->  PreNest = [Term|PNT],
        post2pre(T, [[E,Term]|PNT], Pre)
    ;   binary_op(E)
    ->  PreNest = [Term2,Term1|PNT],
        post2pre(T, [[E,Term1,Term2]|AP], Pre)
    ;   post2pre(T, [E|PreNest], Pre)
    ).
post2pre([], PreNest, Pre) :-
    flatten(PreNest, Pre).

unary_op(X) :-
    memberchk(X, [sin, cos, tan]).

binary_op(X) :-
    memberchk(X, [+, -, /, *]).
在上面的代码中,“原子术语”被隐式定义为任何不是运算符的东西

根据示例:

| ?- post2pre([1,2,3,+,*,sin],Pre).

Pre = [sin,*,1,+,2,3]

yes
在这种情况下,
展平之前的“中间”嵌套形式是:

[sin, [*, 1, [+, 2, 3]]]
上述代码的非if-then-else版本可以编写如下。我选择了上面的if-then-else构造,因为它避免了冗余地检查操作符:

post2pre(Post, Pre) :-
    post2pre(Post, [], Pre).

post2pre([E|T], PreNest, Pre) :-
    atomic_term(E),
    post2pre(T, [E|PreNest], Pre).
post2pre([E|T], [Term|PNT], Pre) :-
    unary_op(E)
    post2pre(T, [[E,Term]|PNT], Pre).
post2pre([E|T], [Term2,Term1|PNT], Pre) :-
    binary_op(E)
    post2pre(T, [[E,Term1,Term2]|AP], Pre).
post2pre([], PreNest, Pre) :-
    flatten(PreNest, Pre).

atomic_term(X) :-  % This defines a term explicitly as anything but an operator
    \+ unary_op(X),
    \+ binary_op(X).

unary_op(X) :-
    memberchk(X, [sin, cos, tan]).

binary_op(X) :-
    memberchk(X, [+, -, /, *]).

我已经运行了link I post中指定的代码。但问题是我的大脑仍然无法用prolog的方式思考。我认为gnu编译器不支持append/2函数。我在互联网上到处寻找Append函数,他们用Append/3实现这两个函数有什么不同?你能告诉我这是怎么回事吗!操作员在这里使用?@AbdulRehman,SWI Prolog具有
append/2
append/3
<代码>附加/3
也在GNU序言中。如果您在SWI Prolog站点上查找这些谓词的描述,您将看到不同之处。简单的回答是,
append/2
假设第一个参数是一个“列表列表”,并将其附加到一个列表中(第二个参数)
append/3
在单个列表级别运行,第三个参数表示附加到第一个参数末尾的第二个参数。注意,对于这些谓词中的每一个,您都可以给它任何参数,它将为其余的生成解决方案。
| ?- post2pre([1,2,3,+,*,sin],Pre).

Pre = [sin,*,1,+,2,3]

yes
[sin, [*, 1, [+, 2, 3]]]
post2pre(Post, Pre) :-
    post2pre(Post, [], Pre).

post2pre([E|T], PreNest, Pre) :-
    atomic_term(E),
    post2pre(T, [E|PreNest], Pre).
post2pre([E|T], [Term|PNT], Pre) :-
    unary_op(E)
    post2pre(T, [[E,Term]|PNT], Pre).
post2pre([E|T], [Term2,Term1|PNT], Pre) :-
    binary_op(E)
    post2pre(T, [[E,Term1,Term2]|AP], Pre).
post2pre([], PreNest, Pre) :-
    flatten(PreNest, Pre).

atomic_term(X) :-  % This defines a term explicitly as anything but an operator
    \+ unary_op(X),
    \+ binary_op(X).

unary_op(X) :-
    memberchk(X, [sin, cos, tan]).

binary_op(X) :-
    memberchk(X, [+, -, /, *]).