我怎样才能用警卫重写这个Haskell,而不需要任何证据?

我怎样才能用警卫重写这个Haskell,而不需要任何证据?,haskell,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 expres

下面列出了一个函数的三个版本#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
我想知道我是否可以摆脱案件陈述,改用警卫。我可以在案件陈述中使用警卫,我发现这很有效:

-- #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
这会产生以下错误。似乎我需要一些东西来询问值类型的东西是否也是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)

如何修复这些错误并实现无案例、仅保护的实现?

如果使用以下方法重新定义类型

然后你可以做:

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
你的#1的问题是,普通的守卫只能是布尔表达式,它没有简洁匹配模式的能力。因此,
IntVal vc
不能作为一个整体工作。即使是这样,从
IntVal vc
模式获得的
vc
也不能用作
Bool
值-为此,您需要
BoolVal vc
模式

但是,您可以使用:

评估(如果ec et ef)s0

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

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

我发现
vt
st
vf
sf
的命名更难理解,因为我必须自己跟踪这些变量的数据流。不给它们命名可以简化理解。

这很好。例如,我是如何理解这一点的,“如果且仅当
IntVal
vc
合并,则为错误。如果且仅当
BoolVal-True
是从
vc
强制执行的,则为(vt,st)。如果且仅当
BoolVal-False
是从
vc
强制执行的,则为(vf,sf)。@AndrewK:,只是这是一种模式匹配,不是强迫。更准确的说法是“如果且仅当
vc
匹配
IntVal
”,或者“
vc
的形式为
IntVal
”。此外,如果有人提到这一点,您可以通过添加
{-#语言模式卫士}
pragma到文件的开头。@AndrewK啊,对了,我想它还没有对图案保护进行必要的分析。虽然你应该能够使用普通的保护
;否则在最后一行中,因为你没有在右边使用任何匹配的变量。@AndrewK图案保护是自Haskell 2010年以来的标准,默认情况下它们应该是可用的,除非您使用的是非常旧的GHC版本或明确选择了
Haskell 98
。正如厄尔詹·约翰森所示,PatternGuards是可能的,但IMO
case
在这里更可取,因为您所做的只是匹配备选方案。您反对该解决方案的理由是什么?很好,正如我所说的当然,我上面写的代码是从用LaTex编写的一些操作语义中逐项提取的。当我在家的时候,我会看看从您的实现向后工作是否会产生更清晰的语义。谢谢:)虽然我可以很好地理解这一点来使用它,但我并不是真的在摸索编译器是如何看待它的。这有一个术语吗
MyType{MySubtype1::MySubtype2}
我可以用谷歌搜索的表单?@AndrewK这是一种所谓的记录语法。你可以阅读它。
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
evaluate (If ec et ef) s0 =
    case evaluate ec s0 of
    (True,  sc) -> evaluate et sc
    (False, sc) -> evaluate ef sc