模式匹配仅具有一个构造函数的类型

时间:2014-05-20 21:21:57

标签: haskell types constructor pattern-matching lazy-evaluation

如果我对一个类型只有一个构造函数的表达式进行模式匹配,那还是会强制运行时将表达式计算为WHNF吗?


我做了一个似乎表明它没有评估的实验:

Prelude> data Test = Test Int Int
Prelude> let errorpr () = error "Fail"
Prelude> let makeTest f = let (x,y) = f () in Test x y
Prelude> let x = makeTest errorpr
Prelude> let Test z1 z2 = x
Prelude> :sprint z1
z1 = _
Prelude> :sprint z2
z2 = _
Prelude> :sprint x
x = _

我原本应该得到一个错误或者:sprint x得到

x = Test _ _

但事实并非如此。


显然我不明白“让”是如何运作的。请参阅下面的答案

2 个答案:

答案 0 :(得分:6)

Prelude> let x = makeTest errorpr
Prelude> let Test z1 z2 = x

最后一行不会强制评估任何内容:let中的模式(隐式)懒惰模式(也称为无可辩驳的模式)。尝试改为

Prelude> let x = makeTest errorpr
Prelude> case x of Test z1 z2 -> "hello!"
Prelude> :sprint x

你应该注意Test _ _之类的东西,因为case中的模式不是懒惰的。{1}}。相比之下,

Prelude> let x = makeTest errorpr
Prelude> case x of ~(Test z1 z2) -> "hello!"   -- lazy pattern!
Prelude> :sprint x

应仅打印_,就像使用let时一样。

以上适用于data类型。相反,newtype不提升内部类型,而是直接使用相同的表示。也就是说,newtype值构造和模式匹配在运行时是 no-ops :它们在类型检查后大致被编译器擦除。

答案 1 :(得分:3)

(由于提到了许多构造函数的可能性,我推测该问题涉及data类型。如果使用newtype,答案会有所不同。请参阅注释。)

是的,它会的。试试例如:

data T = C Int                                                                  

unT (C n) = 42                                                                  

main = print $ unT undefined

你会得到一个未定义的异常,而不是42。

但当然这取决于模式。如果您将unT的定义替换为:

unT ~(C n) = 42

使用延迟模式,结果将为42.另外,请注意let表达式中使用的构造函数模式(例如,let (C n) = something也等同于惰性模式。


关于问题的其余部分,makeTest会生成一个Test值,其参数未被使用。如果它们已被使用,您当然会收到错误(例如,您使用print代替:sprint)。 x未给出Test _ _的原因是因为第5行中的let表达式对应于惰性模式(Haskell 98报告中的第3.12节)。就像你写了let ~(Test z1 z2) = x一样。因此,永远不会评估x