8

由于newtypes 在编译期间被有效地删除,它们没有 thunk,只有值。那么如果我使用 WHNF 请求它会发生什么rseq?例如在

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!我们可以将 a 的 WHNF anewtype简单地定义为未修改的值,并且它是一致的。所以我认为问题是,WHNF 是如何为newtypes 定义的?还是没有严格的定义,并且“这是内部的WHNF”行为被简单地假设为显而易见的事情?

4

1 回答 1

8

根据报告中有关数据类型重命名的部分,

与代数数据类型不同,newtype 构造函数 N 是未提升的,因此 N ⊥ 与 ⊥ 相同。

这里

Sum ⊥ = ⊥

所以新类型的弱头范式是包裹类型的WHNF,并且

Sum (lengthyComputation :: Int) `using` rseq

评估lengthyComputation(当整个表达式被评估时,一个单纯的绑定

let x = Sum (lengthyComputation :: Int) `using` rseq

当然不是,但是没有 newtype 构造函数也是一样的)。

的定义方程seq

seq ⊥ b  =  ⊥
seq a b  =  b, if a ≠ ⊥

因此

seq (Sum ⊥) b = ⊥

并且在

seq (lengthyComputaton :: Int) b

需要seq找出(对不起拟人化)是否lengthyComputation :: Int是⊥。为此,它必须评估lengthyComputation :: Int.


重新更新:

newtypes 是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

匹配总是成功的,并且不评估任何内容。构造函数只强制类型和“模式匹配”它不强制值的类型。

seq很神奇,它不能在 Haskell 中实现。您可以在 Haskell 中编写与上述类型相同的函数seq,但不能为 (polymorphic)编写函数,因为 newtype 构造函数上的“模式匹配”并不严格。您必须匹配包装类型的构造函数,但对于多态,您没有它们。dataseqMaybenewtypenewtype

于 2012-12-02T13:00:48.657 回答