2015-02-23 55 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