创建@< BIP在prolog中

时间:2012-04-01 17:12:47

标签: list prolog compare

我基本上试图创建'我自己'版本的@< prolog中的运算符,即at_less(F1,F2)的调整,如果F1 @它返回true

一些示例输入:

?- at_less(1.2,0)
yes
?-at_less(0,1.2)
no
?-at_less(f(1,2,a),f(1,2,b)).
yes

显然我不想使用@<运营商,因为这将是多余的:) 我可以理解如何比较两个原子,比如

%atom_pr(+A1,+A2): A1 @< A2, where A1 and A2 are atoms.

atom_pr(L1,L2):-
    atom_codes(L1,First), %atom codes for first
    atom_codes(L2,Second),%atom codes for second
    code_compare(First,Second). %compare the codes, return true or false

code_compare([HF|TF],[HS|TS]):-
    (   HF=HS ->
    code_compare(TF,TS)
    ;
    HF<HS ->
    true
    ;
    fail
    ).
code_compare([],X):-
    true.
code_compare([],[]).

%(I understand this is probably not the most efficient way of going about this, but I'm %just beginning!)

我能为所有常数做些类似的东西,而不仅仅是原子吗?是否有类似于atom_codes / 2的命令?如果没有,我唯一能想到的就是把它分成很多if - &gt; else语句,检查第一个是原子而第二个不是等等,但这似乎是一种单调乏味/差的方法呢?

提前感谢您的帮助!

编辑:感谢下面的帮助,我得到了一个正常运行的程序(至少从我能说的内容)。我把它放在下面的代码中,以防其他人在这里徘徊。但我认为这是非常低效的,所以还有很大的改进空间:)

%flat_pr(+F1, +F2): F1@<F2, where F1 and F2 are flat ground terms
flat_pr(F1,F2):-

    (   compound(F1) ->   %these ifs here to check what type F1 and F2 are
    (   compound(F2) ->   %comparing/succeeding/failing as appropriate
    compound_compare(F1,F2) %(atom>integer>float>compound)
    ;                       % I believe these ifs could definitely be cut down though
    (   atom(F2) ->
    true
    ;
    (   float(F2) ->
    true
    ;
    (   integer(F2) ->
    true
    )
    )
    )
    )
    )

    ;

    (   atom(F1) ->
    (   compound(F2) ->
    false

    ;
    (   atom(F2) ->
    atom_pr(F1,F2)
    ;
    (   float(F2) ->
    false
    ;
    (   integer(F2) ->
    false
    )
    )
    )
    )
    )

    ;

    (   float(F1) ->
    (   compound(F2) ->
    false

    ;
    (   atom(F2) ->
    true

    ;
    (   float(F2) ->
    number_pr(F1,F2)
    ;
    (   integer(F2) ->
    true
    )
    )
    )
    )
    ;
    fail
    )

    ;

    (   integer(F1) ->
    (   compound(F2) ->
    false

    ;
    (   atom(F2) ->
    true

    ;
    (   float(F2) ->
    false

    ;
    (   integer(F2) ->
    number_pr(F1,F2)
    )
    )
    )
    )
    )
    .

compound_compare(F1,F2):-  %compares compounds (arity first)
    functor(F1,N1,A1),    %get arity
    functor(F2,N2,A2),
        (   A1<A2 ->      %compare arity
    true
    ;
    (   A1>A2 ->
    false
    )
    ;
    (   A1=A2 ->      %if arity the same
    F1 =.. L1,       %compound -> list
    F2 =.. L2,
    list_compare(L1,L2)  %compare the lists
    )
    )
    .

list_compare([],[]).  %base case
list_compare([H|T],[H1|T1]):-
    (   flat_pr(H,H1) ->    %if H@<H1
    list_compare(T,T1)     %compare Tails
    ;
    false               %else false
    )
    .

atom_pr(L1,L2):-
    atom_codes(L1,First), %atom codes for first
    atom_codes(L2,Second),%atom codes for second
    code_compare(First,Second). %compare the codes, return true or false

number_pr(L1,L2):-   %simple number comparison...straight forward
    (   L1=<L2 ->
    true
    ;
    fail
    ).

code_compare([HF|TF],[HS|TS]):- %just runs through atom codes
    (   HF=HS ->
    code_compare(TF,TS)
    ;
    HF<HS ->
    true
    ;
    fail
    ).
code_compare([],X):-
    true.
code_compare([],[]).

我很想看到改善这个的方法!干杯

1 个答案:

答案 0 :(得分:1)

不确定BIN-Prolog,但在SWI-Prolog中,atom_codes可以解决问题:

?- atom_codes('jack\&^',K). 
K = [106, 97, 99, 107, 38, 94].

?- atom_codes('17.2345',K). 
K = [49, 55, 46, 50, 51, 52, 53].

<强>更新 如果你需要比较术语,1)冻结它们(进一步参见)使术语接地,2)使用unif(= ..)将术语转换为列表,例如,f(1,2)变为[f, 1,2],然后对于每个元素:a)如果它是原子或数字,则使用atom_codes; b)如果是一个术语,则递归地应用相同的过程。

冻结确保变量按其外观顺序进行比较。通过“冻结”,我的意思是从经典的Sterling和Shapiro的书“Prolog的艺术”中得到以下谓词:

numvars('#VAR'(N),N,N1) :- N1 is N+1.
numvars(Term,N1,N2) :- nonvar(Term), functor(Term,_,N),
                          numvars(0,N,Term,N1,N2).
numvars(N,N,_,N1,N1).
numvars(I,N,Term,N1,N3) :- I<N, I1 is I+1,
          arg(I1,Term,Arg), numvars(Arg,N1,N2),
          numvars(I1,N,Term,N2,N3).

frz(A,B) :- frz(A,B,0).
frz(A,B,Min) :- copy_term(A,B), numvars(B,Min,_),!.