Haskell Data.Maybe *** 异常:Maybe.fromJust:无
Haskell Data.Maybe *** Exception: Maybe.fromJust: Nothing
我尝试为练习编写一个程序。如果它可以根据给定的语法解析字符串,它应该读取一个字符串和 return 一个空列表。如果字符串不是有效语法,它应该 return "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))
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
也是部分函数,您更喜欢像这样使用模式匹配,以避免在字符串为空时出现运行时异常,例如:
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 的一个很好的惯用实现!)
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
,这很容易忘记。完全忘记这些功能并改为依赖模式匹配要简单得多(见下文)。
.. == False
应该重写为 not ..
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.next()
) 之前检查数据是否存在 (x.hasNext()
) .忘记检查会导致运行时错误/异常。使用模式匹配,这两个步骤组合在同一个语言结构中,因此无法 "forget" 检查并使程序崩溃。
与原始代码不同,match x (Just [])
不会崩溃,而是 returns Nothing
。
我尝试为练习编写一个程序。如果它可以根据给定的语法解析字符串,它应该读取一个字符串和 return 一个空列表。如果字符串不是有效语法,它应该 return "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))
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
也是部分函数,您更喜欢像这样使用模式匹配,以避免在字符串为空时出现运行时异常,例如:
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 的一个很好的惯用实现!)
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
,这很容易忘记。完全忘记这些功能并改为依赖模式匹配要简单得多(见下文)。 .. == False
应该重写为not ..
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.next()
) 之前检查数据是否存在 (x.hasNext()
) .忘记检查会导致运行时错误/异常。使用模式匹配,这两个步骤组合在同一个语言结构中,因此无法 "forget" 检查并使程序崩溃。
与原始代码不同,match x (Just [])
不会崩溃,而是 returns Nothing
。