由于newtype
在编译期间被有效删除,因此它们没有thunk,只有值。那么如果我使用rseq
要求其WHNF会怎样?例如在
Sum (lengthyComputation :: Int) `using` rseq
其中Sum
定义为
newtype Sum a = Sum { getSum :: a }
会lengthyComputation
得到评估吗?它是否在某处指定/记录,以便我可以指望它?
更新:让我更详细地解释一下我的疑惑。直觉上有人说:“newtype
非常严格,因此它的WHNF就是包含在里面的WHNF”。但我觉得这是一个非常不精确的捷径,而且推理并不那么明确。让我举个例子:
对于标准data
类型,WHNF可以定义为一个表单,我们知道哪个构造函数用于构造值。例如,如果我们没有seq
,我们可以创建自己的
seqMaybe :: Maybe a -> b -> b
seqMaybe Nothing = id
seqMaybe _ = id
并且类似地对于任何data
类型,仅通过其一个构造函数上的模式匹配。
现在让我们来看看
newtype Identity a = Identity { runIdentity :: a }
并创建一个类似的seqIdentity
函数:
seqIdentity :: Identity a -> b -> b
seqIdentity (Identity _) = id
显然,这里没有任何东西被强制给WHNF。 (毕竟,我们总是知道使用了什么构造函数。)编译后,seqIdentity
将与const id
相同。事实上,不可能创建多态seqIdentity
,以便强制评估Identity
内包含的值!我们可以将newtype
的WHNF定义为仅未修改的值,并且它将是一致的。所以我认为问题是,WHNF如何为newtype
定义?或者没有严格的定义,“它是什么内部的WHNF”的行为被简单地假设为显而易见的东西?
答案 0 :(得分:8)
根据报告中Datatype renamings的部分
与代数数据类型不同,newtype构造函数N是未提升的,因此N⊥与⊥相同。
下面
Sum ⊥ = ⊥
所以newtype的弱头正常形式是包装类型的WHNF,并且
Sum (lengthyComputation :: Int) `using` rseq
评估lengthyComputation
(当评估整个表达时,仅仅是绑定
let x = Sum (lengthyComputation :: Int) `using` rseq
当然没有,但没有newtype构造函数也是如此。)
seq
的{{3}}是
seq ⊥ b = ⊥
seq a b = b, if a ≠ ⊥
因此
seq (Sum ⊥) b = ⊥
并在
seq (lengthyComputaton :: Int) b
seq
需要找出(对不起拟人化)lengthyComputation :: Int
是否为{。为此,它必须评估lengthyComputation :: Int
。
重新更新:
newtype
是 unlifted ,这意味着构造函数在语义上不是值构造函数(仅在语法上)。与newtype
构造函数上的模式匹配相比,data
构造函数上的模式匹配不严格。给定
newtype Foo a = Foo { unFoo :: a } -- record syntax for convenience below
“模式匹配”
function :: Foo a -> Bar
function (Foo x) = whatever x
完全等同于
function y = let x = unFoo y in whatever x
匹配总是成功,并且什么都不评估。 defining equations和“模式匹配”取消强制值的类型。
seq
是神奇的,它无法在Haskell中实现。对于seq
类型,您可以编写与data
相同的函数,例如上面的seqMaybe
,在Haskell中,但不能用于(多态)newtype
,因为newtype构造函数的“模式匹配”并不严格。您必须匹配包装类型的构造函数,但对于多态newtype
,您没有它们。