【问题标题】:Haskell Wikibook - Generalized Algebraic Data Types Exercise - Maybe and EitherHaskell Wikibook - 广义代数数据类型练习 - Maybe and Either
【发布时间】:2018-11-20 16:17:56
【问题描述】:

this page of the Haskell Wikibook 上有一个练习,可让您使用 Maybe 和 Either 完成一个场景(大概是为了表明用例非常痛苦)。

练习是:

data Expr = I Int
        | B Bool           -- boolean constants
        | Add Expr Expr
        | Mul Expr Expr
        | Eq  Expr Expr    -- equality test

eval :: Expr -> Maybe (Either Int Bool)
-- Your implementation here.

解决方案的第一行是 - 我认为 - 直截了当:

data Expr = I Int         -- integer constants
          | B Bool        -- boolean constants
          | Add Expr Expr -- add two expressions
          | Mul Expr Expr -- multiply two expressions
          | Eq  Expr Expr -- equality test
          deriving (Show)

eval :: Expr -> Maybe (Either Int Bool)
eval (I n) = Just $ Left n
eval (B b) = Just $ Right b
eval (Add e1 e2) = ...
eval (Mul e1 e2) = ...
eval (Eq e1 e2) = ...

但我不确定如何定义其余部分。举个例子,我猜对于add,我需要解压缩每个表达式的fromLeftfromJust,但我不确定如何正确执行此操作(使用模式匹配?)

提前致谢!

【问题讨论】:

    标签: haskell


    【解决方案1】:

    是的,使用模式匹配,甚至可能是 Maybe monad。

    您可以仅使用模式匹配来实现 eval (Add e1 e2) 分支:

    eval (Add e1 e2) = case eval e1 of
        Just (Left i1) -> case eval e2 of
            Just (Left i2) -> Just (Left (i1 + i2))
            _ -> Nothing
        _ -> Nothing
    

    对一对的模式匹配是减少嵌套case 语句数量的一种好方法:

    eval (Add e1 e2) = case (eval e1, eval e2) of
        (Just (Left i1), Just (Left i2)) -> Just (Left (i1 + i2))
        _ -> Nothing
    

    或者,您可以使用 Maybe monad 作为对那些 case 语句的抽象。如果do 块绑定中的任何模式匹配失败(由于Maybe monad 如何实现fail),它将自动返回Nothing

    eval (Add e1 e2) = do
        Left i1 <- eval e1
        Left i2 <- eval e2
        return (Left (i1 + i2))
    

    【讨论】:

    • Pairs 非常适合降低模式匹配的复杂性。上面的第一个块可以重写为case (eval e1, eval e2) of { (Just (Left i1), Just (Left i2)) -&gt; Just (Left (i1 + i2)); _ -&gt; Nothing }
    • @ChrisSmith 不错!我补充说
    【解决方案2】:

    eval (加 e1 e2) = ...

    您需要评估e1e2,然后对这些结果进行模式匹配。有多种方法可以做到这一点。例如,您可以使用let 绑定。

    let ev1 = eval e1
        ev2 = eval e2 
    in  
    

    然后使用case 构造进行模式匹配。或者如果你喜欢没有let 绑定,你可以这样做

    case (eval e1, eval e2) of 
    

    并在该对上进行模式匹配。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多