簡體   English   中英

將數字統一到Prolog中的列表

[英]Unifying a number to a list in Prolog

好吧,所以我正在做作業,這應該是一個四功能計算器,它接受一個字符串列表,例如[三,三,二],並輸出一個數字。 它只考慮初始列表中從1到20的數字。 以下代碼是我自己的。 它一直運行到將列表中的最后一項(我一直在對其進行測試,但問題出在任何輸入上)取為數字,然后將其統一。

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 :僅str2num(one, 1). 而不是str2num(one, X):- X is 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] 

但是您需要從calculator刪除reverse調用:

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

您擁有幾乎正確的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) ,謂詞將失敗。只有一個數字的列表總數就是數字本身:

func([X], X).

現在整個工作正常了:

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

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

我采用的方法是從定義算術表達式的語法開始。 定義語法的“標准”方式是左遞歸。 由於prolog進行遞歸下降解析,因此語法不能為左遞歸。 每次迭代都必須從令牌流中刪除某些內容,以免您陷入無限遞歸的死亡螺旋。 這是我的像您一樣的4危險計算器的非左遞歸語法:

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運算符:

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/3的“開始符號”。 expr/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
  .                                    %

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM