我怎样才能用警卫重写这个Haskell,而不需要任何证据?
下面列出了一个函数的三个版本#2和#3工作#2是我现在的第一选择。我想找到一些让#1发挥作用的方法,看看它们之间的比较。它在底部 首先,我有这种类型:我怎样才能用警卫重写这个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
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是可能的,但IMOcase
在这里更可取,因为您所做的只是匹配备选方案。您反对该解决方案的理由是什么?很好,正如我所说的当然,我上面写的代码是从用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