Postfix中的前缀转换与sin cos tan的一元运算符等

时间:2014-02-10 14:23:41

标签: data-structures prolog stack logic

我是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).

但我不知道如何处理一元经营者?

2 个答案:

答案 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, [+, -, /, *]).