[英]Haskell Data.Maybe *** Exception: Maybe.fromJust: Nothing
我嘗試編寫一個練習程序。 如果它可以根據給定的語法解析String,則它應該讀取一個String並返回一個空列表。 如果字符串的語法無效,則應返回“ Nothing”。 像這兒:
>prog "c+c*c$"
Just""
>prog "c+c-c$"
Nothing
我寫了以下函數,它們在GHCI中加載和編譯,但是當我使用任何參數運行prog
,都會得到以下異常: *** Exception: Maybe.fromJust: Nothing
我想我以錯誤的方式訪問或傳遞Maybe字符串,但不確定在哪里。 歡迎提供有關正確處理Maybe結構的幫助。
這是我的代碼:
import Data.Maybe
match :: Char -> Maybe String -> Maybe String
match x input
| (isNothing input == False) && (x == head (fromJust(input))) = Just (tail (fromJust(input)))
| otherwise = Nothing
prog :: String -> Maybe String
prog x = match '$' (expr (Just (x)))
expr :: Maybe String -> Maybe String
expr x = ttail (term x)
term :: Maybe String -> Maybe String
term x = ftail (factor x)
ttail :: Maybe String -> Maybe String
ttail x
| fromJust(x) == [] = Just []
| otherwise = ttail (term (match '+' x))
factor :: Maybe String -> Maybe String
factor x = match 'c' x
ftail :: Maybe String -> Maybe String
ftail x
| fromJust(x) == [] = Just []
| otherwise = ftail ( factor ( match '*' x))
OP的代碼中有幾種反模式。 我只討論這個片段。
match :: Char -> Maybe String -> Maybe String
match x input
| (isNothing input == False) && (x == head (fromJust(input))) = Just (tail (fromJust(input)))
| otherwise = Nothing
isNothing, fromJust
是一個反模式,因為后者是一個部分函數,當喂入Nothing
時會使程序崩潰。 程序員必須小心,始終isJust
事先檢查isJust
,這很容易忘記。 完全忘記這些功能,而改為依靠模式匹配要容易得多(請參見下文)。 .. == False
應該改寫為not ..
not (isNothing ..)
isJust ..
not (isNothing ..)
應該是isJust ..
(但同樣,模式匹配使這一點毫無意義) head,tail,!!
也是部分函數,應在可能的情況下將其替換為模式匹配。 在上方,可能會在[]
上調用head
,因此我們需要事先進行檢查。 模式匹配避免了需要。 .. == []
可以使用null ..
(或更好的模式匹配)。 f(x)
,括號沒有任何作用。 -Wall
標志打開警告:編譯器通常會在代碼中發現問題。 如果您正在學習Haskell,我強烈建議您不要使用危險的部分函數,而是閱讀有關模式修補的教程,使用它可以防止代碼中的幾乎所有問題。
為了進行比較,可以將上面的代碼重寫為:
match :: Char -> Maybe String -> Maybe String
match x (Just (y:ys)) | x==y = Just ys
match _ _ = Nothing
請注意,模式匹配如何同時檢查參數是否為內部帶有非空列表的Just
,並提取構造函數中的數據。 如果失敗,則采用下一種匹配情況(而不是使程序崩潰)。
在沒有模式匹配(比如Java的)語言,常常庫迫使我們記得要檢查數據是否存在( x.hasNext()
之前訪問數據( x.next()
忘記檢查會導致運行時錯誤/異常。 使用模式匹配時,這兩個步驟以相同的語言結構組合在一起,因此無法“忘記”檢查並使程序崩潰。
與原始代碼不同, match x (Just [])
不會崩潰,而是返回Nothing
。
fromJust
期望傳遞一個Just
值,並接收一個Nothing
值,這就是為什么發生此異常的原因:
http://hackage.haskell.org/package/base-4.11.1.0/docs/Data-Maybe.html#v:fromJust
請注意,我鼓勵您使用maybe
函數,該函數可以幫助澄清我認為的代碼(並...可能會發現錯誤:))
另外, maybe
它比fromJust
更可取,因為它不是部分函數(即,保證該函數在運行時不會出錯)
例如,它允許您重寫:
match :: Char -> Maybe String -> Maybe String
match x input
| (isNothing input == False) && (x == head (fromJust(input))) = Just (tail (fromJust(input)))
| otherwise = Nothing
如
match :: Char -> Maybe String -> Maybe String
match x input =
maybe
Nothing
(\i ->
if x == head i
then Just $ tail i
else Nothing)
input
還有一件事: head
和tail
也是部分函數,您更喜歡使用這種模式匹配,例如,當String為空時避免運行時異常:
match :: Char -> Maybe String -> Maybe String
match x input =
maybe
Nothing
(\i -> case i of
[] -> Nothing
first:rest ->
if x == first
then Just rest
else Nothing)
input
(編輯:另請參見@chi的答案,該答案提供了一個很好的習俗性的match實現!)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.