将数字统一到Prolog中的列表

时间:2014-02-21 06:13:19

标签: prolog

好吧,所以我正在做一个家庭作业,这应该是一个四功能计算器,例如输入一个字符串列表[三次,两次],并输出一个数字。它只考虑初始列表中从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.

2 个答案:

答案 0 :(得分:2)

小样式评论:使用str2num/2的事实:仅str2num(one, 1).而不是str2num(one, X):- X is 1.等。增加的好处是现在谓词可以双向使用,例如{{1} }。

至于主要问题,你几乎是正确的。

整个str2num(Word, 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] 删除对reverse的来电:

calculator

你几乎正确calculator(X,Total):- numberize(X,L), func(L,Total). 谓词。一个问题:在Prolog中你应该有大括号左右分离:

func

第二个问题:当你的列表减少到一个数字时(考虑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)谓词将会失败。你需要解决的所有问题就是规则列表1号码本身就是数字:

func([3], Total)

现在整个事情都有效:

func([X], X).

答案 1 :(得分:2)

我接近这个的方法是首先定义算术表达式的语法。定义语法的“标准”方式是左递归的。由于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

%--------------------------------------------------------------------
% we can calculate a result if Expr is a valid expression
% that consumes all the available tokens in the token stream
%---------------------------------------------------------------------
calculate(Expr,Result) :- expr( Expr , Result , [] ) .

调用语法的“起始符号”expr/3expr/3(以及其他工作者谓词)几乎是语法的直接重述,还需要他们需要交回输入令牌流的未消耗部分。如果在一天结束时令牌流为空,则解析成功:

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
  .                                 %

乘法词的工作谓词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
  .                                    %