我是Prolog的新手。我想学习这个。我正在构建一个前缀转换谓词的后缀。我搜索了很多google和github等prolog递归语法非常混乱。通过搜索我只是found this one link on stackoverflow。我正在解决同样的问题,但指定的解决方案非常令人困惑。 append / 2函数的实现并没有出现在我的脑海中,还有一下的一元运算符呢?现在已经超过3天,我一直在努力解决这个问题而且只是被吸了。任何人请帮助我实现这个逻辑或任何书籍参考或一些链接,以更好地理解同一问题。谢谢
我想以这种方式解决它
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).
但我不知道如何处理一元经营者?
答案 0 :(得分:2)
好吧,正如我在那个答案中所建议的那样,pos2pre / 2只是一个草图,由学生完成。但它也是一个棘手的解决方案,非常相似的声明。因此,它很容易扩展到处理一元运算符(我将isop / 1重命名为is_binary_op / 1,以清理代码):
pos2pre(Pos, Pre) :-
append([A, B, [O]], Pos), is_binary_op(O), A \= [], B \= [],
pos2pre(A, APre),
pos2pre(B, BPre),
!, append([[O], APre, BPre], Pre).
pos2pre(Pos, Pre) :-
append([A, [O]], Pos), is_unary_op(O), A \= [],
pos2pre(A, APre),
!, append([[O], APre], Pre).
pos2pre([P], [P]).
is_binary_op(O) :- memberchk(O,[+,*]).
is_unary_op(O) :- memberchk(O,[sin,tan]).
测试
?- pos2pre([1,2,3,+,*,sin],Pre) .
Pre = [sin, *, 1, +, 2, 3].
我尝试遵循的另一种方法是使用完全不同的方案,构建 infix 表达式解析器(DCG),然后让后缀/前缀访问树之间转换格式。
编辑这里是从SWI-Prolog库中窃取的追加/ 2谓词(列表):
append(ListOfLists, List) :-
must_be(list, ListOfLists),
append_(ListOfLists, List).
append_([], []).
append_([L|Ls], As) :-
append(L, Ws, As),
append_(Ls, Ws).
!符号被命名为 cut ,它不是运算符,而是系统谓词(更准确地说,是控件谓词)。它总是成功,并且修剪替代品可能在执行点挂起,从而承诺到目前为止做出的选择。您应该在线阅读一些关于此主题的documentation ...
答案 1 :(得分:0)
这是备用版本。这个首先从后缀列表构建前缀结构作为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
在这种情况下,flatten
出现之前的“中间”嵌套表单将是:
[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, [+, -, /, *]).