首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Data.Maybe *例外: Maybe.fromJust: Nothing

Data.Maybe *例外: Maybe.fromJust: Nothing
EN

Stack Overflow用户
提问于 2018-07-01 19:26:00
回答 2查看 1.9K关注 0票数 1

我试着写一个练习的程序。如果可以根据给定的语法解析字符串,则应该读取字符串并返回空列表。如果字符串不在有效语法中,则应该返回"Nothing“。就像这里:

代码语言:javascript
复制
>prog "c+c*c$"
Just""
>prog "c+c-c$"
Nothing

我编写了以下函数,它们是在GHCI中加载和编译的,但是当我使用任何参数运行prog时,会得到以下异常:*** Exception: Maybe.fromJust: Nothing

我想我以一种错误的方式访问或传递一个可能的字符串,但不确定在哪里。任何关于正确处理结构的帮助都是受欢迎的。

这是我的代码:

代码语言:javascript
复制
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))
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-07-01 20:03:40

OP的代码中有几个反模式。我只会讨论这个片段。

代码语言:javascript
复制
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,这很容易被忘记。完全忘记这些函数,转而依赖模式匹配(见下文)要简单得多。
  • .. == False应该重写为not ..
  • not (isNothing ..)应该是isJust .. (但同样,模式匹配使得这没有意义)
  • head,tail,!!也是部分函数,如果可能的话,应该用模式匹配代替它们。上面,head可能在[]上被调用,所以我们需要事先检查它。模式匹配避免了这种需要。
  • 而不是.. == [],我们可以使用null .. (或者更好的模式匹配)。
  • 永远不要为函数调用编写f(x),括号在这里没有意义。
  • 使用-Wall标志打开警告:编译器经常会发现代码中的问题。

如果您正在学习Haskell,我强烈建议您不要使用危险的部分函数,并阅读关于模式修补的教程,使用该教程可以防止代码中的几乎所有问题。

作为比较,上面的代码可以重写为:

代码语言:javascript
复制
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

票数 9
EN

Stack Overflow用户

发布于 2018-07-01 19:45:50

fromJust期望被传递一个Just值并接收一个Nothing值,这就是为什么会发生这种异常:

http://hackage.haskell.org/package/base-4.11.1.0/docs/Data-Maybe.html#v:fromJust

请注意,我鼓励您使用maybe函数,这将有助于澄清我认为的代码(以及.也许可以找到bug :)

此外,maybefromJust更可取,因为它不是一个部分函数(即保证该函数在运行时不会出错)

例如,它允许您重写:

代码语言:javascript
复制
match :: Char -> Maybe String -> Maybe String
match x input
  | (isNothing input == False) && (x == head (fromJust(input))) = Just (tail (fromJust(input)))
  | otherwise = Nothing

作为

代码语言:javascript
复制
match :: Char -> Maybe String -> Maybe String
match x input =
  maybe
    Nothing
    (\i ->
      if x == head i
        then Just $ tail i
        else Nothing)
    input

还有一件事:headtail也是部分函数,您更愿意使用这样的模式匹配来避免运行时异常,例如,当字符串为空时:

代码语言:javascript
复制
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的一个很好的惯用实现!)

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/51126343

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档