2014-02-10 49 views
2

我想在Haskell中實現一個RPN caculator。這是來自Learn You a Haskell的練習。 這裏是我的代碼:在一個RPN caculator實現中的Haskell問題

import Data.List 
solveRPN :: String -> Int 
solveRPN str = head $ foldl putStack [] (words str) 
     where putStack accumulator token 
      | token == "+" = pFunction (+) 
      | token == "-" = pFunction (-) 
      | token == "*" = pFunction (*) 
      | token == "/" = pFunction (`div`) 
      | otherwise = accumulator ++ [read token :: Float] 
      where pFunction function = (int $ init accumulator) ++ [function argu1 argu2] 
        argu1 = last accumulator 
        argu2 = last $ init accumulator 

功能solveRPN第一分割字符串爲標記。 (例如:"4 3 2 + *"["4","3","2","+","*"]) 然後,將一個一個的令牌推入堆棧。如果它遇到一個操作員,堆棧中的最後兩個項目由操作員處理,然後將生成的值放回堆棧。當遍歷整個列表時,堆棧中只剩下一個項目,這就是答案。

這裏有一些問題:

  1. (int $ init accumulator)我想取消在堆棧中的最後兩個元素。有沒有其他替代(int $ init accumulator)

  2. 該代碼無法通過編譯。 GHC說:「輸入解析錯誤(」
    在這一行:| token == "/" = pFunction ( div )。我懷疑問題可能來自pFunction。它的參數是一個運算符(或者我可以稱它爲函數?),我不知道是否。?「函數作爲函數的參數」,在Haskell是法律這是法律是否有任何替代

  3. 我的確在GHCI一些實驗,發現一些奇怪的事情:

Prelude> let plus = (+) 
Prelude> :t (+) 
(+) :: Num a => a -> a -> a 
Prelude> :t plus 
plus :: Integer -> Integer -> Integer 

加號的類型與(+)的類型有什麼不同?

感謝您的關注和耐心。 (:

+0

您一直在堆棧上使用必須遍歷整個堆棧的操作。你有沒有考慮倒轉你的堆棧? 'init'變成'tail','last'變成'head','stack ++ [x]'變成'x:stack',所以大部分堆棧操作變成O(1)。我想你不太關心表現,但這是值得思考的。 – user2407038

+0

是的,這是一個好主意。實際上,Learn You a Haskell提供的答案使用您所描述的堆棧。 –

回答

2

(int $ init accumulator)

您的意思是init $ init accumulator話雖這麼說,你可以寫你自己的dropLast2函數,該函數一樣init . init但遍歷該列表僅一次,有點像

dropLast2 :: [a] -> [a] 
dropLast2 []  = [] 
dropLast2 [_]  = [] 
dropLast2 [_,_] = [] 
dropLast2 (x:xs) = x : dropLast2 xs 

代碼不能通過編譯。

 | token == "/" = pFunction (`div`) 

您正在使用反引號(')才能使用的功能有兩個參數爲綴功能。但是,通過在div附近使用圓括號,您可以立即取消它,這既有點偏差,也有解析器錯誤。只需使用

 | token == "/" = pFunction div 

代替。但是,有一件重要的事情。div的類型是

div :: Integral a => a -> a -> a 

然而,你的蓄電池是Float名單。 div不可能對這些工作。然而,FloatFractional類的一個實例,所以你可以簡單地使用(/)

(/) :: Fractional a => a -> a -> a 

因此獲得

 | token == "/" = pFunction (/) 

我的確在GHCI一些實驗,發現了一些奇怪的

(+)Num類的一部分。您的plus不是任何功能的一部分,GHC會嘗試推斷其類型。然後monomorphism restriction啓動。有關更多信息,請參見Type error while writing max function

1

關於你提到的第一個問題:

我得到你周圍使用列表走錯了路的印象。如果您推送堆棧中的某個元素,則應使用:運算符將其添加到列表中。彈出前兩個元素,然後變成drop 2 stack,我認爲這更好。

這樣做也會更有效率,因爲:是恆定時間操作,而++與第一個參數(即堆棧的大小)是線性的。

+0

謝謝你,這是一個好點 –