簡體   English   中英

Haskell數據。也許是***例外:也許是來自於。

[英]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

還有一件事: headtail也是部分函數,​​您更喜歡使用這種模式匹配,例如,當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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM