模拟基本错误,Erlang

模拟基本错误,Erlang,erlang,Erlang,我有个错误,我不明白为什么。 因此,如果我进入: proj:calc([{push,{num,2}},{push,{num,3}},{plus},{push,{num,4},{mul}]) 而守则: calc(List) -> [Res] = lists:foldl(fun calc/2, [], List), Res. calc({plus}, [N1, N2 | Stack]) -> [N1 + N2 | Stack]; calc({mul}, [N1, N2 | Stack

我有个错误,我不明白为什么。 因此,如果我进入:

proj:calc([{push,{num,2}},{push,{num,3}},{plus},{push,{num,4},{mul}])

而守则:

calc(List) -> 
[Res] = lists:foldl(fun calc/2, [], List),
Res.

calc({plus}, [N1, N2 | Stack]) -> [N1 + N2 | Stack];
calc({mul}, [N1, N2 | Stack]) -> [N1 * N2 | Stack];
calc({push,{num,X}}, Stack) -> [X | Stack].
calc(List) -> 
[Res] = lists:foldl(fun calc/2, [], List),
Res.

calc({plus},{pop},{ret}, [N1, N2 | Stack]) -> [N1 + N2 | Stack];
calc({mul},{pop},{ret}, [N1, N2 | Stack]) -> [N1 * N2 | Stack];
calc({push,{num,X}}, Stack) -> [X | Stack].
我得到了20的输出(正是我想要的)

但如果我有这样的输入:

calc({{plus},{pop},{ret}}, [N1, N2 | Stack]) -> [N1 + N2 | Stack];
calc({{mul},{pop},{ret}}, [N1, N2 | Stack]) -> [N1 * N2 | Stack];
calc({push,{num,X}}, Stack) -> [X | Stack].
proj:calc([{push,{num,2}},{push,{num,3},{plus},{pop},{ret},{push,{num,4},{mul},{pop},{ret}])

而守则:

calc(List) -> 
[Res] = lists:foldl(fun calc/2, [], List),
Res.

calc({plus}, [N1, N2 | Stack]) -> [N1 + N2 | Stack];
calc({mul}, [N1, N2 | Stack]) -> [N1 * N2 | Stack];
calc({push,{num,X}}, Stack) -> [X | Stack].
calc(List) -> 
[Res] = lists:foldl(fun calc/2, [], List),
Res.

calc({plus},{pop},{ret}, [N1, N2 | Stack]) -> [N1 + N2 | Stack];
calc({mul},{pop},{ret}, [N1, N2 | Stack]) -> [N1 * N2 | Stack];
calc({push,{num,X}}, Stack) -> [X | Stack].
我得到一个错误:

异常错误:没有与proj:calc({pop},[5]匹配的函数子句


我是二郎的新手,为什么会发生这种情况,我该如何解决

折叠、映射或过滤器的每次迭代只消耗列表中的一个元素。这里有三个元素表示单个操作:
{plus}、{pop}、{ret}
。您要么必须将其封装在一个元组中,要么记住堆栈机器在每个操作结束时都会隐式执行
{pop}
{ret}
,因此可以删除这两个操作

考虑到这一点,您的代码应该以第一种方式阅读,或者如下所示:

calc({{plus},{pop},{ret}}, [N1, N2 | Stack]) -> [N1 + N2 | Stack];
calc({{mul},{pop},{ret}}, [N1, N2 | Stack]) -> [N1 * N2 | Stack];
calc({push,{num,X}}, Stack) -> [X | Stack].
您的输入应该是:

[{push,{num,2}},{push,{num,3}},{{plus},{pop},{ret}},{push,{num,4}},{{mul},{pop},{ret}}]
传递给映射函数的函数必须是arity 2,这里您在同一个函数定义中混合了arity 4的两个子句和arity 2的一个子句,这是不合法的


在任何情况下,您所描述的系列都是堆栈机器固有的,不需要详细说明。这就是为什么您的实现始终比大多数示例看起来更复杂/问题更大。

谢谢,我知道当我尝试所有方法时它都不起作用。我也尝试过使用过滤器,但我不知道如何正确地实现它,否则它将无法正常工作。过滤器会根据测试结果进行过滤,留下列表的其余部分。映射通过对列表的每个成员应用一个操作来转换列表。您试图做的是将列表中的所有值压缩成一个值,这就是折叠所做的:它在最后将所有内容折叠成一个值(聚合操作)。恰好可以将堆栈机器的每个操作定义为单个函数,并且由于fold本身已经完成了“pop、operation、push、iterate”步骤,因此很容易用fold构建堆栈机器。或者在
calc/2
中为
{plus}
{mul}
{pop}使用单独的子句
{ret}
。请注意,不需要将这些指令作为元组,它们也可以是
plus
mul
pop
ret