我對 haskell 完全陌生,并在網上看到了有關如何添加錯誤處理的示例,但我不確定如何將其合并到我的背景關系中。下面是在嘗試處理錯誤之前作業的代碼示例。
expr'::Parser Double
expr' = term' `chainl1'` addop
term'::Parser Double
term' = factor' `chainl1` mulop
chainl :: Parser a -> Parser (a -> a -> a) -> a -> Parser a
chainl p op a = (p `chainl1` op) <|> pure a
chainl1 ::Parser a -> Parser (a -> a -> a) -> Parser a
chainl1 p op = p >>= rest
where
rest a = (do
f <- op
b <- p
rest (f a b)) <|> pure a
addop, mulop :: Parser (Double -> Double -> Double)
我已經將其擴展為在發現不規則的情況下允許addop并mulop回傳錯誤訊息。這會導致函式定義更改為:
addop, mulop :: Parser (Either String (Double -> Double -> Double))
在其他編程語言中,我會檢查是否f <- op是字串并回傳字串。但是我不確定如何在 Haskell 中解決這個問題。這個想法是這個錯誤訊息一直回傳到term'. 因此它的功能定義最終也需要改變。這一切都是為了構建一個 Monadic Parser。
uj5u.com熱心網友回復:
如果您正在使用,parsec那么您可以使您的代碼更通用以使用ParsecTmonad 轉換器:
import Text.Parsec hiding (chainl1)
import Control.Monad.Trans.Class (lift)
expr' :: ParsecT String () (Either String) Double
expr' = term' `chainl1` addop
term' :: ParsecT String () (Either String) Double
term' = factor' `chainl1` mulop
factor' :: ParsecT String () (Either String) Double
factor' = read <$> many1 digit
chainl1 :: Monad m => ParsecT s u m a -> ParsecT s u m (a -> a -> a) -> ParsecT s u m a
chainl1 p op = p >>= rest
where
rest a = (do
f <- op
b <- p
rest (f a b))
<|> pure a
addop, mulop :: ParsecT String () (Either String) (Double -> Double -> Double)
addop = ( ) <$ char ' ' <|> (-) <$ char '-'
mulop = ((*) <$ char '*' <* lift (Left "error")) <|> (/) <$ char '/' <|> (**) <$ char '^'
我不知道你想要回傳什么樣的錯誤,所以如果輸入中遇到“*”,我就犯了一個錯誤。
您可以像這樣運行決議器:
ghci> runParserT (expr' <* eof) () "buffer" "1 2 3"
Right (Right 6.0)
ghci> runParserT (expr' <* eof) () "buffer" "1 2*3"
Left "error"
uj5u.com熱心網友回復:
基于parsec實作的答案。
其實運營商<|>就是你所需要的。它處理任何決議錯誤。在運算式中,a <|> b如果決議器a失敗,則決議器b將運行(預計決議器a在失敗之前是否消耗了一些輸入;對于處理這種情況,您可以使用try像這樣的組合器:)try a <|> b。
但是,如果您想根據錯誤型別處理錯誤,那么您應該像@Noughtmare 一樣回答。但是我建議你這樣做:
定義錯誤型別。處理錯誤將是無誤的。
data MyError = ME_DivByZero | ...如果為決議器定義型別別名,則可以簡化型別簽名。
type MyParser = ParsecT String () (Either MyError)然后簽名將如下所示:
expr' :: MyParser Double addop, mulop :: MyParser (Double -> Double -> Double)使用
throwError拋出你的錯誤,catchError來處理你的錯誤,那將是更地道。所以它看起來像這樣:f <- catchError op $ \case ME_DivByZero -> ... ME_... -> ... err -> throwError err -- rethrow error
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/316803.html
下一篇:使用組合來獲得除法的上限
