[英]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.