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