我从Learn You Some Erlang for great good!学习Erlang,并尝试在反向波兰表示法计算器中实现阶乘函数。到目前为止,我有这个:
-module(rps).
-export([calculate/1]).
calculate(List) ->
calculate(List, []).
calculate([], [ Number ]) ->
Number;
calculate([ Head | Tail ], Stack) ->
case Head of
"+" ->
[ B, A | Rest ] = Stack,
calculate(Tail, [ A + B | Rest ]);
"-" ->
[ B, A | Rest ] = Stack,
calculate(Tail, [ A - B | Rest ]);
"*" ->
[ B, A | Rest ] = Stack,
calculate(Tail, [ A * B | Rest ]);
"/" ->
[ B, A | Rest ] = Stack,
calculate(Tail, [ A / B | Rest ]);
"!" ->
[ A | Rest ] = Stack,
calculate(Tail, [ factorial(A) | Rest ]);
_ ->
calculate(Tail, [ Head | Stack ])
end.
factorial(N) ->
factorial(N, 1).
factorial(0, Accumulator) ->
Accumulator;
factorial(N, Accumulator) when N >= 0 ->
factorial(N - 1, Accumulator * N).
现在问题在于我的factorial / 2函数,特别是N = 0
的基本情况。只要堆栈上的第一个元素是整数,它就可以正常工作,例如:
5> rpcalc:calculate([1, 2, "+", "!"]).
6
但是我注意到除非两个参数都是整数,结果是一个整数,所以除非总是返回一个浮点数,例如:
7> 4 / 2.
2.0
所以有时浮标出现在我的堆栈上。然后,即使它们是正数和整数,我的因子也会失败,如0.0 =/= 0
。效果是:
13> rpcalc:calculate([6, 2, "/", "!"]).
** exception error: no function clause matching rpcalc:factorial(-1.0,0.0) (rpcalc.erl, line 33)
in function rpcalc:calculate/2 (rpcalc.erl, line 25)
在这里支持积极的整体花车最优雅的方式是什么?我的直觉是在factorial/1
中有一个案例可以检测到这些数字并将它们转换为整数,但也许有更好的方法?
答案 0 :(得分:1)
存在div
,它采用整数并执行整数除法。你可以把它写成:
calculate([], [ Number ]) ->
Number;
calculate([ "+" | Tail ], [ B, A | Rest ]) ->
calculate(Tail, [ A + B | Rest ]);
calculate([ "-" | Tail ], [ B, A | Rest ]) ->
calculate(Tail, [ A - B | Rest ]);
calculate([ "*" | Tail ], [ B, A | Rest ]) ->
calculate(Tail, [ A * B | Rest ]);
calculate([ "/" | Tail ], [ B, A | Rest ])
when is_integer(A), is_integer(B), A rem B =:= 0 ->
calculate(Tail, [ A div B | Rest ]);
calculate([ "/" | Tail ], [ B, A | Rest ]) ->
calculate(Tail, [ A / B | Rest ]);
calculate([ "!" | Tail ], [ A | Rest ]) ->
calculate(Tail, [ factorial(A) | Rest ]);
calculate([ Head | Tail ], Stack) ->
calculate(Tail, [ Head | Stack ]).
答案 1 :(得分:1)
经过一番思考之后,我自己对此有所了解:
factorial(N) ->
factorial(float_to_integer(N), 1).
factorial(0, Accumulator) ->
Accumulator;
factorial(N, Accumulator) when N >= 0 ->
factorial(N - 1, Accumulator * N).
float_to_integer(N) when is_integer(N) ->
N;
float_to_integer(N) when is_float(N) ->
Integer = trunc(N),
case N == Integer of
true ->
Integer;
false ->
error(badarg)
end.
我添加了一个名为float_to_integer
的帮助程序,它为任何整数返回一个整数,否则会抛出错误。这个名称有点误导,因为它也可以处理整数。然后我用它来后卫 factorial/1
。