如何使用没有案例的警卫重写这个Haskell?

时间:2014-09-23 02:45:04

标签: haskell

我有三个版本的功能,如下所示。 #2和#3工作。 #2现在是我的第一选择。我想找到一些让#1工作的方法,看看它是如何比较的。它在底部。

首先,我有这种类型:

data Value =
    IntVal Int
  | BoolVal Bool
  deriving (Show)

这个(a的工作片段)功能:

-- #2
evaluate (If ec et ef) s0 =
  case vc of
    (IntVal ____) -> error "Conditional expression in If statement must be a boolean" 
    (BoolVal vcb) -> if vcb then (vt, st)
                            else (vf, sf)
  where (vc, sc) = evaluate ec s0
        (vt, st) = evaluate et sc
        (vf, sf) = evaluate ef sc

我想知道我是否可以摆脱案件陈述并使用警卫代替。我可以在case语句中使用guards ,我发现这有效:

-- #3
evaluate (If ec et ef) s0 =
  case vc of
    (IntVal _) -> error "Conditional expression in If statement must be a boolean" 
    (BoolVal vcb) | vcb       -> (vt, st)
                  | otherwise -> (vf, sf)
  where (vc, sc) = evaluate ec s0
        (vt, st) = evaluate et sc
        (vf, sf) = evaluate ef sc

很高兴知道。我认为#2最清楚地传达了我的意图。尽管如此,这是我尝试的第一件事,我想弄清楚它是如何实际运作的:

-- #1
evaluate (If ec et ef) s0 
  | (IntVal vc) = error "Conditional expression in If statement must be a boolean" 
  | vc == True  = (vt, st)
  | otherwise   = (vf, sf)
  where (vc, sc) = evaluate ec s0
        (vt, st) = evaluate et sc
        (vf, sf) = evaluate ef sc

这会产生以下错误。看起来我需要一些东西来询问Value类型的某些东西是否也是IntVal子类型?:

Couldn't match expected type `Int' with actual type `Value'
In the first argument of `IntVal', namely `vc'
In the expression: (IntVal vc)

--------------------------------------------------------------------------------

Couldn't match expected type `Bool' with actual type `Value'
In the expression: (IntVal vc)
In a stmt of a pattern guard for
               an equation for `evaluate':
  (IntVal vc)

如何解决这些错误并实施无案例,仅限警卫?

3 个答案:

答案 0 :(得分:5)

这不是一个真正的答案,但我写的是这样的事情:

evaluate (If ec et ef) s0 =
    case evaluate ec s0 of
    (True,  sc) -> evaluate et sc
    (False, sc) -> evaluate ef sc

我发现vtstvfsf的命名更难以阅读,因为我必须自己跟踪这些变量的数据流。保持他们的匿名简化了理解。

答案 1 :(得分:4)

你的#1的问题在于,普通的守卫只能是布尔表达式,它们无法简洁地匹配模式。所以IntVal vc不会像一个人一样工作。即使这样做,您从vc模式获得的IntVal vc也不能用作Bool值 - 您需要BoolVal vc模式。

但是,您可以使用pattern guards

evaluate (If ec et ef) s0
  | IntVal _      <- vc = error "Conditional expression in If statement must be a boolean" 
  | BoolVal True  <- vc = (vt, st)
  | BoolVal False <- vc = (vf, sf)
  where (vc, sc) = evaluate ec s0
        (vt, st) = evaluate et sc
        (vf, sf) = evaluate ef sc

答案 2 :(得分:1)

如果您使用record syntax重新定义类型Value

data Value = IntVal { unInt :: Int } | BoolVal { unBool :: Bool }

然后你可以这样做:

evaluate (If ec et ef) s0 =
  if unBool vc then (vt, st) else (vf, sf)
  where (vc, sc) = evaluate ec s0
        (vt, st) = evaluate et sc
        (vf, sf) = evaluate ef sc