我需要写出(而不是计算)数字列表的所有状态,这意味着:
输入:
Numbers: 1,2,3
Operators: +,-,/,*输出:
1+2+3
1-2-3
1/2/3
1*2*3
1+2-3
1+2/3
1+2*3
1-2+3
1-2/3
1-2*3
1/2+3
1/2-3
1/2+3
1*2+3
1*2-3
1+2-3在下降代码中只显示1+2+3
我怎样才能把它们发展到所有的州?
list_sum([Item], Item).
list_sum([Item1,Item2 | Tail], Total) :-
list_sum([Item1+Item2|Tail], Total).发布于 2019-01-31 15:13:18
卡洛·卡佩利( Carlo Capelli )发布的一个很好的解决方案的一个变体,让我们可以演示一个有用的编程成语,以更好地利用第一个参数索引:
list_combine([N1| Ns], Os, Nt) :-
list_combine(Ns, N1, Os, Nt).
list_combine([], N, _, [N]).
list_combine([N2| Ns], N1, Os, [N1, O| Nt]) :-
member(O, Os),
list_combine(Ns, N2, Os, Nt).我们的想法是传递我们想要走的列表,将列表头与尾部分开,并将两者作为参数传递,尾作为第一个参数,如上面所示。
在最初的解决方案中,Prolog编译器通常不会区分只有一个元素的列表和一个或多个元素的列表。但它将区分空列表(原子)和具有至少一个元素(复合项)的列表。还请注意,除了对list_combine/3谓词调用的预期选择点之外,原始版本还为每个递归调用创建了一个虚假的选择点。
发布于 2019-01-31 14:16:16
简单的递归:
list_combine([N|Nr],Os,[N,O|Nt]) :-
member(O,Os),
list_combine(Nr,Os,Nt).
list_combine([N],_,[N]).而现在
?- forall(list_combine([1,2,3],[+,*],C),writeln(C)).
[1,+,2,+,3]
[1,+,2,*,3]
[1,*,2,+,3]
[1,*,2,*,3]
true.这里有一个-也许-更易读的版本。
list_combine(Ns,Os,Cs) :-
[N|Nr] = Ns,
member(O,Os),
Cs = [N,O|Nt],
list_combine(Nr,Os,Nt).当然,在替代中使用,只是为了更好地理解统一在分解和合成参数中的作用。
发布于 2019-01-31 12:33:56
operator --> [+].
operator --> [-].
operator --> [*].
operator --> [/].
expr_trinary -->
[1],
operator,
[2],
operator,
[3].
expr(E) :-
phrase(expr_trinary,Expr_trinary),
atomics_to_string(Expr_trinary,E).示例运行:
?- expr(E).
E = "1+2+3" ;
E = "1+2-3" ;
E = "1+2*3" ;
E = "1+2/3" ;
E = "1-2+3" ;
E = "1-2-3" ;
E = "1-2*3" ;
E = "1-2/3" ;
E = "1*2+3" ;
E = "1*2-3" ;
E = "1*2*3" ;
E = "1*2/3" ;
E = "1/2+3" ;
E = "1/2-3" ;
E = "1/2*3" ;
E = "1/2/3".由于您的问题适用于list,将DCG视为列表处理的一种方法是使用清单/1将其转换为常规Prolog。
?- listing(operator).
operator([+|A], A).
operator([-|A], A).
operator([*|A], A).
operator([/|A], A).
true.
?- listing(expr_trinary).
expr_trinary([1|A], B) :-
operator(A, C),
C=[2|D],
operator(D, E),
E=[3|B].
true.它可以被称为常规Prolog。
?- expr_trinary(E,[]).
E = [1, +, 2, +, 3] ;
E = [1, +, 2, -, 3] ;
E = [1, +, 2, *, 3] ;
E = [1, +, 2, /, 3] ;
E = [1, -, 2, +, 3] ;
E = [1, -, 2, -, 3] ;
E = [1, -, 2, *, 3] ;
E = [1, -, 2, /, 3] ;
E = [1, *, 2, +, 3] ;
E = [1, *, 2, -, 3] ;
E = [1, *, 2, *, 3] ;
E = [1, *, 2, /, 3] ;
E = [1, /, 2, +, 3] ;
E = [1, /, 2, -, 3] ;
E = [1, /, 2, *, 3] ;
E = [1, /, 2, /, 3].在任何位置使用一个数字(1,2,3)的扩展解决方案:
number --> [1].
number --> [2].
number --> [3].
operator --> [+].
operator --> [-].
operator --> [*].
operator --> [/].
expr_trinary -->
number,
operator,
number,
operator,
number.
expr(E) :-
phrase(expr_trinary,Expr_trinary),
atomics_to_string(Expr_trinary,E).示例运行:
?- expr(E).
E = "1+1+1" ;
E = "1+1+2" ;
E = "1+1+3" ;
E = "1+1-1" ;
E = "1+1-2" ;
E = "1+1-3" ;
...有关如何使用DCG生成的说明,请参阅以下阿姆齐部分:用差异列表生成
在对其他答复的评论中你写道:
它不起作用超过三个元素?你能为更多的元素开发它吗?
随着元素数量的增加,组合爆炸也会增加。
为了保持组合爆炸在示例中的运行这将只使用两个数字(1,2)和两个运算符(+,*),您可以添加更多您喜欢的。
number(1) --> [1].
number(2) --> [2].
operator(+) --> [+].
operator(*) --> [*].
expr(N) --> number(N).
expr((E1,Op,E2)) --> operator(Op),expr(E1),expr(E2).
expr(E) :-
length(Expr,_),
phrase(expr(E),Expr).注意,这将长度/2用于迭代深化。基本上,length/2生成增加长度的列表,然后短语/2给出了这个长度的答案。
?- length(Ls,N).
Ls = [],
N = 0 ;
Ls = [_870],
N = 1 ;
Ls = [_870, _876],
N = 2 ;
Ls = [_870, _876, _882],
N = 3 ;
Ls = [_870, _876, _882, _888],
N = 4 ;
Ls = [_870, _876, _882, _888, _894],
N = 5 ;
Ls = [_870, _876, _882, _888, _894, _900],
N = 6
...这样,生成器就能像预期的那样工作--正常的BNF和DCG。
<expr> ::= <expr> <op> <expr>
expr((E1,Op,E2)) --> expr(E1),operator(Op),expr(E2).哪个是直接左递归被转换为
<expr> ::= <op> <expr> <expr>
expr((E1,Op,E2)) --> operator(Op),expr(E1),expr(E2).示例运行:
?- expr(E).
E = 1 ;
E = 2 ;
E = (1, (+), 1) ;
E = (1, (+), 2) ;
E = (2, (+), 1) ;
E = (2, (+), 2) ;
E = (1, (*), 1) ;
E = (1, (*), 2) ;
E = (2, (*), 1) ;
E = (2, (*), 2) ;
E = (1, (+), 1, (+), 1) ;
...
E = (1, (+), 2, (+), 2, (*), 1) ;
E = (1, (+), 2, (+), 2, (*), 2) ;
E = (1, (+), (1, (+), 1), (+), 1) ;
E = (1, (+), (1, (+), 1), (+), 2) ;
E = (1, (+), (1, (+), 2), (+), 1) ;
...https://stackoverflow.com/questions/54456357
复制相似问题