2015-02-23 49 views
1

我有一个错误,我不明白为什么。 所以,如果我进入:模拟基本错误,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]) -> [N1 * N2 | Stack]; 
calc({push,{num,X}}, Stack) -> [X | Stack]. 

我得到的20的输出(完美的我想要的东西,)。

但是,如果我有一个这样的输入:

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},{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]. 

我得到一个错误:

exception error: no function clause matching proj:calc({pop},[5])

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

回答

3

fold,map或filter的每次迭代只消耗列表中的一个元素。这里有三个元素代表一个操作:{plus},{pop},{ret}。您必须将其包装在单个元组{{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}}] 

传递给map函数的函数必须是arity 2,这里你在同一个函数定义中混合了arity 4和arity 2的两个子句 - 这是不合法的。

在任何情况下,您所描述的系列都是堆叠机器固有的,无需拼写出来。这就是为什么你的实现比大多数例子一直更复杂的外观/问题。

+0

谢谢,我知道这不会工作,当我尝试了一切。我也试图使用过滤器,但我不知道如何正确实施它,否则它就无法工作。 – nothingness 2015-02-23 23:01:59

+0

过滤器根据测试的结果过滤掉所有内容,并保留列表的其余部分。地图通过对列表的每个成员应用一个操作来转换列表。你所要做的就是将列表中的所有值压缩到一个值中,这就是折叠所做的事情:它将所有元素最后折叠成一个值(一个集合操作)。它恰好可以将堆栈机器的每一个动作定义为一个单一的功能,并且由于折叠已经根据它们的性质进行了“弹出,操作,推送,迭代”步骤,所以很容易用折叠来构建堆栈机器。 – zxq9 2015-02-23 23:26:54

+0

晶莹剔透,并得到程序工作。 ty :) – nothingness 2015-02-23 23:48:40