在Prolog中将数字统一到列表

在Prolog中将数字统一到列表,prolog,Prolog,好的,我正在做一个家庭作业,这应该是一个四功能计算器,比如输入一个字符串列表[3,乘以2],然后输出一个数字。它只考虑初始列表中从1到20的数字。下面的代码都是我自己的。它一直运行到我用来测试它的列表中最后一项的位置,但问题是numberize中的任何输入都不会统一 calculator([twenty, times, three, plus, five, divided_by, two],Total). 我知道解决方案一定很简单,但我在Prolog中还没有足够的经验来解决这个问题 我的问题是

好的,我正在做一个家庭作业,这应该是一个四功能计算器,比如输入一个字符串列表[3,乘以2],然后输出一个数字。它只考虑初始列表中从1到20的数字。下面的代码都是我自己的。它一直运行到我用来测试它的列表中最后一项的位置,但问题是numberize中的任何输入都不会统一

calculator([twenty, times, three, plus, five, divided_by, two],Total).
我知道解决方案一定很简单,但我在Prolog中还没有足够的经验来解决这个问题

我的问题是:如何修复代码,使其按我希望的方式运行

calculator(X,Total):-
   numberize(X,L),
   reverse(L,L1),
   func(L1,Total).

numberize([X,Y|T],L):-
   str2num(X,X1),
   numberize(T,[Y,X1|L]).

numberize([X],L):-
   str2num(X,X1),
%somehow add on the X1 to the front of L without any errors and it's golden
/*Whatever that line is*/L is [X1|L].

func([X1,X,Z1|T], Total):-
   (X == times, times(X1,Z1,Ttl));
   (X == plus, plus(X1,Z1,Ttl));
   (X == divided_by, divided_by(X1,Z1,Ttl));
   (X == minus, minus(X1,Z1,Ttl)),
   func([Ttl|T],Total).

str2num(one, X):- X is 1.
str2num(two, X):- X is 2.
str2num(three, X):- X is 3.
str2num(four, X):- X is 4.
str2num(five, X):- X is 5.
str2num(six, X):- X is 6.
str2num(seven, X):- X is 7.
str2num(eight, X):- X is 8.
str2num(nine, X):- X is 9.
str2num(ten, X):- X is 10.
str2num(eleven, X):- X is 11.
str2num(twelve, X):- X is 12.
str2num(thirteen, X):- X is 13.
str2num(fourteen, X):- X is 14.
str2num(fifteen, X):- X is 15.
str2num(sixteen, X):- X is 16.
str2num(seventeen, X):- X is 17.
str2num(eighteen, X):- X is 18.
str2num(nineteen, X):- X is 19.
str2num(twenty, X):- X is 20.
times(X,Y,Prod):-
   Prod is X*Y.

plus(X,Y,Sum):-
   Sum is X+Y.

divided_by(X,Y,Quo):-
   Quo is X/Y.

minus(X,Y,Dif):-
   Dif is X-Y.

小风格备注:对str2num使用事实/2:仅使用str2numone,1。代替str2numone,X:-X是1,等等。额外的好处是现在谓词可以双向使用,就像str2numWord,1一样

至于主要问题,你几乎是对的

整个numberize谓词可以如此简单:

numberize([X], [N]) :-
    str2num(X, N).
numberize([X, Op | T], [N, Op | NewT]) :-
    str2num(X, N),
    numberize(T, NewT).
让我们测试一下:

?- numberize([one, plus, two, minus, three], L).
L = [1, plus, 2, minus, 3] 
但您需要从计算器中删除反向调用:

您拥有几乎正确的func谓词。一个问题:在Prolog中,在析取处应该有大括号:

func([X1,X,Z1|T], Total):-
    (
        X == times, times(X1,Z1,Ttl)
    ;
        X == plus, plus(X1,Z1,Ttl)
    ;
        X == divided_by, divided_by(X1,Z1,Ttl)
    ;
        X == minus, minus(X1,Z1,Ttl)
    ),
    func([Ttl|T],Total).
第二个问题:当列表缩减为一个数字时,想想func[1,plus,2],Total如何调用func[3],Total谓词将失败。您只需修改一条规则,即只有1个数字的列表的总数就是数字本身:

func([X], X).
现在整件事都起作用了:

?- calculator([one, plus, two], Total).
Total = 3 

?- calculator([one, plus, two, minus, four], Total).
Total = -1 

小风格备注:对str2num使用事实/2:仅使用str2numone,1。代替str2numone,X:-X是1,等等。额外的好处是现在谓词可以双向使用,就像str2numWord,1一样

至于主要问题,你几乎是对的

整个numberize谓词可以如此简单:

numberize([X], [N]) :-
    str2num(X, N).
numberize([X, Op | T], [N, Op | NewT]) :-
    str2num(X, N),
    numberize(T, NewT).
让我们测试一下:

?- numberize([one, plus, two, minus, three], L).
L = [1, plus, 2, minus, 3] 
但您需要从计算器中删除反向调用:

您拥有几乎正确的func谓词。一个问题:在Prolog中,在析取处应该有大括号:

func([X1,X,Z1|T], Total):-
    (
        X == times, times(X1,Z1,Ttl)
    ;
        X == plus, plus(X1,Z1,Ttl)
    ;
        X == divided_by, divided_by(X1,Z1,Ttl)
    ;
        X == minus, minus(X1,Z1,Ttl)
    ),
    func([Ttl|T],Total).
第二个问题:当列表缩减为一个数字时,想想func[1,plus,2],Total如何调用func[3],Total谓词将失败。您只需修改一条规则,即只有1个数字的列表的总数就是数字本身:

func([X], X).
现在整件事都起作用了:

?- calculator([one, plus, two], Total).
Total = 3 

?- calculator([one, plus, two, minus, four], Total).
Total = -1 

我的方法是从定义算术表达式的语法开始。定义语法的标准方法是左递归。由于prolog执行递归下降解析,因此语法不能保持递归。每次迭代都必须从令牌流中删除某些内容,以免陷入无限递归的死亡螺旋。这是我的非左递归语法,适用于像您这样的4-banger计算器:

expression : multiplicative_expression '+' expression
           | multiplicative_expression '-' expression
           | multiplicative_expression
           ;

multiplicative_expression : factor '*' multiplicative_expression
                          | factor '/' multiplicative_expression
                          | factor '%' multiplicative_expression
                          | factor
                          ;

factor : '-' value
       | '(' expression ')'
       | value
       ;

value : number
一旦我们掌握了语法,prolog代码就可以自己编写了。首先,一些需要处理的事实。我们需要一个运算符及其类型的列表,以及等效的prolog运算符:

operator( plus       , additive       , '+'   ) .
operator( minus      , additive       , '-'   ) .
operator( times      , multiplicative , '*'   ) .
operator( divided_by , multiplicative , '/'   ) .
operator( modulo     , multiplicative , 'mod' ) .
和一个单词到数字的映射:

number_word( zero     , 0 ).
number_word( one      , 1 ).
...
number_word( nineteen , 19 ) .
number_word( twenty   , 20 ) .
我们需要我们的接口谓词calculate/2:

调用语法的开始符号expr/3的。expr/3和其他worker谓词基本上是语法的直接重述,另外还需要返回输入令牌流的未使用部分。如果在一天结束时,令牌流为空,则解析成功:

expr( Xs , Result , Tail ) :-       % per the grammar, an expression is
  mult( Xs , LHS , [Sym|X1] ) ,     % - a multiplicative expression, followed by
  operator( Sym , additive , Op ) , % - an infix additive operator, followed by
  expr( X1 , RHS , X2 ) ,           % - another expression
  Term =.. [Op,LHS,RHS] ,           % * in which case, we construct the proper prolog structure
  Result is Term ,                  % * in which case, we evaluate the result in the usual way
  Tail = X2                         % * and unify any remaining tokens with the Tail
  .                                 %
expr( Xs , Result , Tail ) :-       % alternatively, an expression is simply
  mult( Xs , Result , Tail )        % - a single multiplicative expression
  .                                 %
乘法术语的worker谓词mult/3几乎完全相同-直接重述语法:

mult( Xs , Result, Tail ) :-              % a multiplicative expression is
  factor( Xs , LHS , [Sym|X1] ) ,         % - a factor, followed by
  operator( Sym , multiplicative , Op ) , % - an infix multiplicative operator, followed by
  mult( X1 , RHS , X2 ) ,                 % - another factor
  evaluate( Op , LHS , RHS , Result ) ,   % * in which case, we evalute the result in the usual way
  Tail = X2                               % * and unify any remaining tokens with the tail
  .                                       %
mult( Xs , Result , Tail ) :-             % alternatively, a multiplicative expression is simply
  factor( Xs , Result , Tail )            % - a single factor
  .                                       %
最后,由于我们没有使用改变运算符优先级的高优先级操作(如一元减号、幂运算或括号),因此因子只是一个可以转换为整数值的数字字:

factor( [X|Xs] , Value , Xs ) :- % a factor is simply
  number_word(X,Value)           % - a number value (in our case, a word that we convert to an integer)
  .
以及一个简单的助手,用于根据需要计算每个子表达式:

evaluate( Op , LHS , RHS , Result ) :- % to evaluate an infix term,
  Term =.. [Op,LHS,RHS] ,              % - use univ to convert to the correct prolog structure, and
  Result is Term                       % evaluate it as the result
  .                                    %

我的方法是从定义算术表达式的语法开始。定义语法的标准方法是左递归。由于prolog执行递归下降解析,因此语法不能保持递归。每次迭代都必须从令牌流中删除某些内容,以免陷入无限递归的死亡螺旋。这是我的非左递归语法,适用于像您这样的4-banger计算器:

expression : multiplicative_expression '+' expression
           | multiplicative_expression '-' expression
           | multiplicative_expression
           ;

multiplicative_expression : factor '*' multiplicative_expression
                          | factor '/' multiplicative_expression
                          | factor '%' multiplicative_expression
                          | factor
                          ;

factor : '-' value
       | '(' expression ')'
       | value
       ;

value : number
一旦我们掌握了语法,prolog代码就可以自己编写了。首先,一些需要处理的事实。我们需要一个运算符及其类型的列表,以及等效的prolog运算符:

operator( plus       , additive       , '+'   ) .
operator( minus      , additive       , '-'   ) .
operator( times      , multiplicative , '*'   ) .
operator( divided_by , multiplicative , '/'   ) .
operator( modulo     , multiplicative , 'mod' ) .
和一个单词到数字的映射:

number_word( zero     , 0 ).
number_word( one      , 1 ).
...
number_word( nineteen , 19 ) .
number_word( twenty   , 20 ) .
我们需要我们的接口谓词calculate/2:

调用语法的开始符号expr/3的。expr/3和其他worker谓词基本上是语法的直接重述,另外还需要返回输入令牌流的未使用部分。如果在一天结束时,令牌流为空,则解析成功:

expr( Xs , Result , Tail ) :-       % per the grammar, an expression is
  mult( Xs , LHS , [Sym|X1] ) ,     % - a multiplicative expression, followed by
  operator( Sym , additive , Op ) , % - an infix additive operator, followed by
  expr( X1 , RHS , X2 ) ,           % - another expression
  Term =.. [Op,LHS,RHS] ,           % * in which case, we construct the proper prolog structure
  Result is Term ,                  % * in which case, we evaluate the result in the usual way
  Tail = X2                         % * and unify any remaining tokens with the Tail
  .                                 %
expr( Xs , Result , Tail ) :-       % alternatively, an expression is simply
  mult( Xs , Result , Tail )        % - a single multiplicative expression
  .                                 %
乘法术语的worker谓词mult/3几乎完全相同-直接重述语法:

mult( Xs , Result, Tail ) :-              % a multiplicative expression is
  factor( Xs , LHS , [Sym|X1] ) ,         % - a factor, followed by
  operator( Sym , multiplicative , Op ) , % - an infix multiplicative operator, followed by
  mult( X1 , RHS , X2 ) ,                 % - another factor
  evaluate( Op , LHS , RHS , Result ) ,   % * in which case, we evalute the result in the usual way
  Tail = X2                               % * and unify any remaining tokens with the tail
  .                                       %
mult( Xs , Result , Tail ) :-             % alternatively, a multiplicative expression is simply
  factor( Xs , Result , Tail )            % - a single factor
  .                                       %
最后,因为我们不是WRA 对于改变运算符优先级的高优先级操作,如一元减号、幂运算或括号,因子只是一个可以转换为整数值的数字字:

factor( [X|Xs] , Value , Xs ) :- % a factor is simply
  number_word(X,Value)           % - a number value (in our case, a word that we convert to an integer)
  .
以及一个简单的助手,用于根据需要计算每个子表达式:

evaluate( Op , LHS , RHS , Result ) :- % to evaluate an infix term,
  Term =.. [Op,LHS,RHS] ,              % - use univ to convert to the correct prolog structure, and
  Result is Term                       % evaluate it as the result
  .                                    %

我们需要关心操作符优先级吗?换句话说,3加4乘以5等于23还是35?@他们不需要在意。我从OP的同学在这个问题上的例子中知道了这一点:是的,我们不需要它。这是我们给出的另一个例子,所以我想@SergeyDymchenko说另一张海报是同学是对的。但不,我没有,事情本来应该像我做的那样顺利。比str2numone更好、更简单,X:-X为1。。对于其他数字也是如此。我们需要考虑运算符优先级吗?换句话说,3加4乘以5等于23还是35?@他们不需要在意。我从OP的同学在这个问题上的例子中知道了这一点:是的,我们不需要它。这是我们给出的另一个例子,所以我想@SergeyDymchenko说另一张海报是同学是对的。但不,我没有,事情本来应该像我做的那样顺利。比str2numone更好、更简单,X:-X为1。。其他数字也是如此。@Throsby还注意到,只要答案在你翻译的数字范围内,你就可以把它翻译回去,这样你就可以得到?-计算器[一,加,四,减,三],总数。Total=2。@Throsby还注意到,只要答案在你翻译的数字范围内,你就可以把它翻译回去,这样你就可以得到?-计算器[1,加,4,减,3],Total。Total=2。答案很好,但我在寻找解决方案,而不是更好的方案。我应该早点接受第一个答案。对不起,谢谢你!答案很好,但我在寻找解决方案,而不是更好的方案。我应该早点接受第一个答案。对不起,谢谢你!