Haskell数据。可能***例外:可能。fromJust:无

Haskell数据。可能***例外:可能。fromJust:无,haskell,maybe,Haskell,Maybe,我试着写一个练习程序。如果它可以根据给定的语法解析字符串,那么它应该读取一个字符串并返回一个空列表。如果字符串的语法无效,则应返回“Nothing”。就像这里: >prog "c+c*c$" Just"" >prog "c+c-c$" Nothing 我编写了以下函数,它们是在GHCI中加载和编译的,但是当我使用任何参数运行prog时,我得到以下异常:***异常:Maybe.fromJust:Nothing 我想我可能以错误的方式访问或传递字符串,但不确定在哪里。欢迎提供有关正确处

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

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

我想我可能以错误的方式访问或传递字符串,但不确定在哪里。欢迎提供有关正确处理结构的任何帮助

这是我的密码:

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
值,这就是发生此异常的原因:

请注意,我鼓励您使用这个函数,我认为它可以帮助澄清您的代码(并且……可能会找到bug:)

另外,
可能
更可取,因为它不是部分函数(即保证函数在运行时不会出错)

例如,它允许您重写:

match :: Char -> Maybe String -> Maybe String
match x input
  | (isNothing input == False) && (x == head (fromJust(input))) = Just (tail (fromJust(input)))
  | otherwise = Nothing
作为

还有一件事:
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的答案,它提供了一个很好的匹配惯用实现!)

fromJust
希望传递一个
Just
值,而它接收一个
Nothing
值,这就是为什么会发生此异常的原因:

请注意,我鼓励您使用这个函数,我认为它可以帮助澄清您的代码(并且……可能会找到bug:)

另外,
可能
更可取,因为它不是部分函数(即保证函数在运行时不会出错)

例如,它允许您重写:

match :: Char -> Maybe String -> Maybe String
match x input
  | (isNothing input == False) && (x == head (fromJust(input))) = Just (tail (fromJust(input)))
  | otherwise = Nothing
作为

还有一件事:
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的答案,它提供了一个很好的匹配惯用实现!)

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
    馈送时会使程序崩溃。程序员必须事先仔细检查
    是否正确,这很容易忘记。完全忘记这些函数而依赖模式匹配要简单得多(见下文)
  • 。==False
    应重写为
    非..
  • not(isNothing.)
  • 头,尾
    也是部分函数,如果可能,应该用模式匹配替换它们。上面,
    head
    可能在
    []
    上被调用,因此我们需要事先检查它。模式匹配避免了这种需要
  • 而不是
    。==[]
    可以使用
    null..
    (或者更好的是,使用模式匹配)
  • 永远不要为函数调用编写
    f(x)
    ,括号在那里没有任何意义
  • 使用
    -Wall
    标志打开警告:编译器通常会在代码中发现问题
如果您正在学习Haskell,我强烈建议您不要使用危险的分部函数,并阅读关于模式修补的教程,使用该教程可以避免代码中几乎所有的问题

为了进行比较,上述代码可以改写为:

match :: Char -> Maybe String -> Maybe String
match x (Just (y:ys)) | x==y = Just ys
match _ _                    = Nothing
请注意,模式匹配如何同时检查参数是否为
只是
,并在构造函数中提取数据。当它失败时,将执行下一个匹配案例(而不是使程序崩溃)

在没有模式匹配的语言(比如Java)中,库常常迫使我们在访问数据(
x.next()
)之前检查数据是否存在(
x.next()
)。忘记检查会导致运行时错误/异常。在模式匹配中,这两个步骤组合在同一个语言结构中,因此无法“忘记”检查并使程序崩溃


与原始代码不同,
match x(Just[])
不会崩溃,而是返回
Nothing

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
    馈送时会使程序崩溃。程序员必须事先仔细检查
    是否正确,这很容易忘记。完全忘记这些函数而依赖模式匹配要简单得多(见下文)
  • 。==False
    应重写为
    非..
  • not(isNothing.)
  • 头,尾
    也是部分函数,如果可能,应该用模式匹配替换它们。上面,
    head
    可能在
    []
    上被调用,因此我们需要事先检查它。模式匹配避免了这种需要
  • 而不是
    。==[]
    可以使用
    null..
    (或者更好的是,使用模式匹配)
  • 永远不要为函数调用编写
    f(x)
    ,括号在那里没有任何意义
  • 使用
    -Wall
    标志打开警告:编译器通常会在代码中发现问题
如果你在学习Haskell,我强烈建议你