Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/github/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Prolog 序言:将数字附加到术语_Prolog_B Prolog - Fatal编程技术网

Prolog 序言:将数字附加到术语

Prolog 序言:将数字附加到术语,prolog,b-prolog,Prolog,B Prolog,可以直接在术语后面加上数字吗 也就是说,我可以很容易地做这样的事情: ?- A = 1 + 2, B = 3, C = A + B. C = 1+2+3 但是,有没有一种方法(运算符?)在C=a+B中指定某些内容而不是“+”来获得“C=1+23” 我觉得我在要求一些奇怪的东西,所以这里是上下文。我有一个数字列表,我想生成所有可以通过在数字之间放置“+”、“-”或nothing获得的表达式 优点和缺点都是简单的部分: possible([X], X) :- !. possible([A, B |

可以直接在术语后面加上数字吗

也就是说,我可以很容易地做这样的事情:

?- A = 1 + 2, B = 3, C = A + B.
C = 1+2+3
但是,有没有一种方法(运算符?)在
C=a+B
中指定某些内容而不是“+”来获得“C=1+23”

我觉得我在要求一些奇怪的东西,所以这里是上下文。我有一个数字列表,我想生成所有可以通过在数字之间放置“+”、“-”或nothing获得的表达式

优点和缺点都是简单的部分:

possible([X], X) :- !.
possible([A, B | Rest], E) :-
    ( H = A + B ; H = A - B ),
    possible([H | Rest], E).

?- possible([1, 2, 3], E).
E = 1+2+3 ?;
E = 1+2-3 ?;
E = 1-2+3 ?;
E = 1-2-3
yes
但我还想得到“E=12+3”,“E=1+23”和“E=123”。有没有简单的方法


更新:解决方案应该是可移植的,或者至少可以在B-Prolog中使用。

我最初误解了您的问题,只是将其作为使用DCGs的列表处理练习来处理。在我完成DCG之后,我才意识到您试图生成Prolog术语。但我能够通过使用SWI Prolog的字符串处理谓词将列表转换为字符串,然后将字符串转换为术语,从而得到一个可行的解决方案。我很想知道一个更直接的方法来实现这一点

possible(Digits, AsTerm) :-
    phrase(sequence(Digits), Sequence),
    atomics_to_string(Sequence, AsString),
    term_string(AsTerm, AsString).

sequence(Ds) -->
    digits(Ds).
sequence(Ds) --> {append(First, Last, Ds)},
    digits(First), sign, sequence(Last).

digits([D]) -->
    digit(D).
digits([D|Ds]) -->
    digit(D), digits(Ds).

digit(D) --> {integer(D)},
    [D].

sign --> [+].
sign --> [-].
此版本的可能/2将生成可评估的序言术语:

?- possible([1,2,3],X), Y is X.
X = Y, Y = 123 ;
X = 1+23,
Y = 24 ;
X = 1+2+3,
Y = 6 ;
X = 1+2-3,
Y = 0 ;
...

此解决方案不需要字符串到术语的转换。它仍然取决于SWI Prolog谓词
atom\u number/2
(不确定它的可用性有多广)。如果有必要遵守ISO,我认为使用
atom\u code/2
number\u code/2
编写一个自定义
atom\u number/2
谓词就足够了
digital\u added\u to\u expression/3实际上太笼统了,因为它将处理任何以数字作为第二个参数的谓词

digit_appended_to_expression(Expression, C, ExpressionWithC) :-
    Expression =.. [Operator, A, B],
    digit_concat(B, C, BC),
    ExpressionWithC =.. [Operator, A, BC].

digit_concat(A, B, AB) :-
    number(A),
    number(B),
    atom_number(A_Atom, A),
    atom_number(B_Atom, B),
    atom_concat(A_Atom, B_Atom, AB_Atom),
    atom_number(AB_Atom, AB).

possible([X], X) :- !.
possible([A, B | Rest], E) :-
    ( digit_concat(A, B, H)
    ; H = A + B
    ; H = A - B
    ; digit_appended_to_expression(A, B, H)
    ),
    possible([H | Rest], E).
这仍然没有给出运算符,因为它需要一个三位谓词,但如果它真的很重要,可以使用术语扩展来实现宏

足够吗?

这是我的赌注

possible([N|Ns], D) :-
    digits_number([N|Ns], D).
possible([N|Ns], X) :-
    append([L|Ls], [R|Rs], [N|Ns]),
    possible([L|Ls], Lx),
    digits_number([R|Rs], Rx),
    (Op = + ; Op = -), X =.. [Op, Lx, Rx].

digits_number(Digits, N) :-
    maplist(digit_code, Digits, Codes),
    number_codes(N, Codes).
digit_code(D, C) :-
    C is D + 0'0.
详细[N | Ns]等的目的是避免匹配空列表

此处编辑是一个变体,不需要maplist/3和number\u codes/2。代码在大小上非常相似

possible(Ns, D) :-
    digits_number(Ns, _, D).
possible([N|Ns], X) :-
    append([L|Ls], [R|Rs], [N|Ns]),
    possible([L|Ls], Lx),
    digits_number([R|Rs], _, Rx),
    (Op = + ; Op = -), X =.. [Op, Lx,Rx].

digits_number([Digit], 1, Digit).
digits_number([D|Ds], F, N) :-
    digits_number(Ds, G, T),
    F is G * 10,
    N is T + D * F.
它的效率更高(至少在推理计数上),实际上这里有一个性能测试

?- L=[1,2,3,4,5,6,7,8], time(findall(X,possible_1(L,X),L1)), time(findall(X,possible_2(L,X),L2)).
% 31,591 inferences, 0.017 CPU in 0.017 seconds (100% CPU, 1851600 Lips)
% 20,656 inferences, 0.017 CPU in 0.018 seconds (98% CPU, 1192235 Lips)
L = [1, 2, 3, 4, 5, 6, 7, 8],
L1 = L2, L2 = [12345678, 1+2345678, 1-2345678, 12+345678, 12-345678, 1+2+345678, 1+2-345678, ... - ... + 345678, ... - ...|...].

当然,我已经将这两个版本重命名为可能的_1,可能的_2

这个简单且完全可移植的解决方案怎么样:

possible([Digit], Digit).
possible([Digit| Digits], Digit + RightExpression) :-
    possible(Digits, RightExpression).
possible([Digit| Digits], Digit - RightExpression) :-
    possible(Digits, RightExpression).
possible([Digit1, Digit2| Digits], Expression) :-
    Number0 is Digit1 * 10,
    Number is Number0 + Digit2,
    possible([Number| Digits], Expression).
使用B-Prolog进行测试:

$ bp
B-Prolog Version 8.1, All rights reserved, (C) Afany Software 1994-2014.
| ?- [possible].
consulting::possible.pl

yes
| ?- possible([1,2,3], Exp).
Exp = 1+(2+3) ?;
Exp = 1+(2-3) ?;
Exp = 1+23 ?;
Exp = 1-(2+3) ?;
Exp = 1-(2-3) ?;
Exp = 1-23 ?;
Exp = 12+3 ?;
Exp = 12-3 ?;
Exp = 123 ?;
no
关于性能,使用与Carlo回答中相同的基准,我得到:

?- L=[1,2,3,4,5,6,7,8], time(findall(X,possible(L,X),L1)).
% 12,037 inferences, 0.003 CPU in 0.003 seconds (93% CPU, 4223509 Lips)
L = [1, 2, 3, 4, 5, 6, 7, 8],
L1 = [1+ (2+ (3+ (4+ (5+ (6+ (7+8)))))), 1+ (2+ (3+ (4+ (5+ (6+ (7-8)))))), 1+ (2+ (3+ (4+ (5+ (6+78))))), 1+ (2+ (3+ (4+ (5+ (... - ...))))), 1+ (2+ (3+ (4+ (... + ...)))), 1+ (2+ (3+ (... + ...))), 1+ (2+ (... + ...)), 1+ (... + ...), ... + ...|...].
以下是使用蓄能器的可能(双关语)解决方案:

%numberexp( D, N, XN) :- number_chars( D, DL), DL=[ DC| _], number_chars( N, NL), number_chars( XN, [ DC| NL]).
numberexp( D, N, XN) :- XN is integer( exp( log( 10)*(1+integer( log( 10, N))))*D+N).


poss( [ H], H, Z, Z).
poss( [ H| T], H, Z, E) :- poss( T, F, F, XT), E= Z+XT.
poss( [ H| T], H, Z, E) :- poss( T, F, F, XT), E= Z-XT.
poss( [ H| T], A, Z, E) :- poss( T, F, Z,  E), numberexp( H, F, A).

possible( L, E) :- poss( L, F, F, E).
无论从哪方面看,数字扩展部分都是丑陋的,但至少它可以是便携的

输出为:

| ?- possible([1,2,3],E).
E = 1+(2+3) ?;
E = 1+(2-3) ?;
E = 1+23 ?;
E = 1-(2+3) ?;
E = 1-(2-3) ?;
E = 1-23 ?;
E = 12+3 ?;
E = 12-3 ?;
E = 123 ?;
no

是的,通过将术语转换为字符串很容易做到,即使没有DCG。但我不想用这种方式,因为不是所有的序言都有术语字符串转换谓词(最初我试图用B-Prolog解决这个问题),而且它看起来非常“非序言”。@SergeyDymchenko但我想你必须这样做,而且你也同意,使用
atom\u concat/3
从数字构建原子?这是我开始解决这个问题的途径。我真的希望有一种更简洁的方法。谓词
atom\u number/2
是专有的,不是官方的或事实上的标准谓词。我明白了,但看起来(相对而言)使用iso谓词编写等效语句很容易。它给我的印象是足够方便,可以保证包含在个人谓词库中。还是有什么特别的原因让我们应该避免使用原子数/2的等价物?(我想我承认了它的非标准性质,是不是把术语弄混了?)?或者只是特定于某些实现(只是SWI?)?谢谢你的帮助。我所说的“专有”是指Prolog方言特有的。当然,这本身没有问题,特别是当您指出,您可以使用标准谓词定义
atom_number/2
谓词时。您能否尝试在我(编辑)的答案中使用性能优化,以避免调用
=../2
?由于您避免调用我正在使用的
number\u codes/2
,因此您的解决方案可以更快一些。这是一个有趣的问题:-)@PauloMoura:你的问题更快,有15859个推论。在开发过程中,我也得到了这些术语,比如
1+(2+3)
,在发布解决方案之前,我设法避免了它们,但最初的问题没有明确说明什么是关于关联性/优先级的首选行为。。。是的,这是一个有趣的问题:)通过我为您的第二个解决方案建议的优化,我得到了12420个推论。只需替换
(Op=+;Op=-),X=。。[Op,Lx,Rx]
带有
(X=(Lx+Rx);X=(Lx-Rx))
。不幸的是,避免
1+(2+3)
解决方案似乎会阻止对
可能的/2
谓词使用尾部递归定义。@PauloMoura:您建议的优化非常好,谢谢。诚恳地说,我不明白为什么推理计数变化如此之大……似乎您想要执行一些系统测试。在这种情况下,最好根据抽象语法树(如n个节点等)而不是具体语法来定义标准,这是您基本上要做的。您能否澄清您是否需要解决方案,如
(1+2)+3
(如Carlo的答案)或
1+(2+3)
(如我的答案)还是两者都有?@PauloMoura我更喜欢(1+2)+3,但只要一直使用,任何形式都可以。我的意思是,在“(1+2)+3”和“1+(2+3)”中,只有一个必须在输出中。当绑定第一个列表元素(正在构造的术语的函子)并且可以枚举其他列表元素时,不需要使用标准的
=../2
内置谓词。对该谓词的调用代价很高(尤其是因为它们需要使用一个临时列表,以后必须对该列表进行垃圾收集),因此应尽可能避免调用。只需编写,例如