首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Prolog:如何生成简单的数学表达式?

Prolog:如何生成简单的数学表达式?
EN

Stack Overflow用户
提问于 2019-01-31 08:36:10
回答 5查看 904关注 0票数 1

我需要写出(而不是计算)数字列表的所有状态,这意味着:

输入:

代码语言:javascript
复制
Numbers: 1,2,3
Operators: +,-,/,*

输出:

代码语言:javascript
复制
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

我怎样才能把它们发展到所有的州?

代码语言:javascript
复制
list_sum([Item], Item).
list_sum([Item1,Item2 | Tail], Total) :-
   list_sum([Item1+Item2|Tail], Total).
EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2019-01-31 15:13:18

卡洛·卡佩利( Carlo Capelli )发布的一个很好的解决方案的一个变体,让我们可以演示一个有用的编程成语,以更好地利用第一个参数索引:

代码语言:javascript
复制
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谓词调用的预期选择点之外,原始版本还为每个递归调用创建了一个虚假的选择点。

票数 5
EN

Stack Overflow用户

发布于 2019-01-31 14:16:16

简单的递归:

代码语言:javascript
复制
list_combine([N|Nr],Os,[N,O|Nt]) :-
    member(O,Os),
    list_combine(Nr,Os,Nt).
list_combine([N],_,[N]).

而现在

代码语言:javascript
复制
?- forall(list_combine([1,2,3],[+,*],C),writeln(C)).
[1,+,2,+,3]
[1,+,2,*,3]
[1,*,2,+,3]
[1,*,2,*,3]
true.

这里有一个-也许-更易读的版本。

代码语言:javascript
复制
list_combine(Ns,Os,Cs) :-
    [N|Nr] = Ns,
    member(O,Os),
    Cs = [N,O|Nt],
    list_combine(Nr,Os,Nt).

当然,在替代中使用,只是为了更好地理解统一在分解和合成参数中的作用。

票数 4
EN

Stack Overflow用户

发布于 2019-01-31 12:33:56

DCG短语/2一起用作生成器

代码语言:javascript
复制
operator --> [+].
operator --> [-].
operator --> [*].
operator --> [/].

expr_trinary -->
  [1],
  operator,
  [2],
  operator,
  [3].

expr(E) :-
    phrase(expr_trinary,Expr_trinary),
    atomics_to_string(Expr_trinary,E).

示例运行:

代码语言:javascript
复制
?- 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。

代码语言:javascript
复制
?- 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。

代码语言:javascript
复制
?- 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)的扩展解决方案:

代码语言:javascript
复制
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).

示例运行:

代码语言:javascript
复制
?- 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)和两个运算符(+,*),您可以添加更多您喜欢的。

代码语言:javascript
复制
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给出了这个长度的答案。

代码语言:javascript
复制
?- 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。

代码语言:javascript
复制
<expr> ::= <expr> <op> <expr>

expr((E1,Op,E2)) --> expr(E1),operator(Op),expr(E2).

哪个是直接左递归被转换为

代码语言:javascript
复制
<expr> ::= <op> <expr> <expr>

expr((E1,Op,E2)) --> operator(Op),expr(E1),expr(E2).

示例运行:

代码语言:javascript
复制
?- 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) ;
...
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/54456357

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档