haskell - 严格声明的意义何在?

标签 haskell lazy-evaluation

我正在启动 Haskell,并正在查看一些数据类型用“!”定义的库。来自字节串库的示例:

data ByteString = PS {-# UNPACK #-} !(ForeignPtr Word8) -- payload
                     {-# UNPACK #-} !Int                -- offset
                     {-# UNPACK #-} !Int                -- length

现在我看到了this question作为对这意味着什么的解释,我想这很容易理解。但我现在的问题是:使用这个有什么意义?既然表达式会在需要时被求值,为什么要强制早期求值呢?

在这个问题的第二个答案中,C.V.汉森说:“[...]有时懒惰的开销可能会太多或浪费”。这是否意味着它用于节省内存(保存值比保存表达式更便宜)?

如果有解释和例子就太好了!

谢谢!

[编辑]我认为我应该选择一个不带 {-# UNPACK #-} 的示例。那么就让我自己做一个吧。这有道理吗?是的,为什么以及在什么情况下?

data MyType = Const1 !Int
            | Const2 !Double
            | Const3 !SomeOtherDataTypeMaybeMoreComplex

最佳答案

这里的目标不是严格性,而是将这些元素打包到数据结构中。如果不严格限制,这三个构造函数参数中的任何一个都可以指向堆分配的值结构或堆分配的延迟求值 thunk。严格来说,它只能指向堆分配的值结构。通过严格和打包结构,可以使这些值内联。

由于这三个值中的每一个都是指针大小的实体,并且无论如何都严格访问,因此在使用此结构时强制使用严格且打包的结构可以节省指针间接寻址。

在更一般的情况下,严格注释可以帮助减少空间泄漏。考虑这样的情况:

data Foo = Foo Int

makeFoo :: ReallyBigDataStructure -> Foo
makeFoo x = Foo (computeSomething x)

如果没有严格注释,如果你只调用 makeFoo,它会构建一个 Foo 指向一个指向 ReallyBigDataStructure 的 thunk,同时保持它在内存中,直到有什么东西迫使 thunk 进行评估。如果我们有

data Foo = Foo !Int

这会强制 computeSomething 计算立即进行(好吧,一旦有东西强制 makeFoo 本身),这会避免留下对 ReallyBigDataStructure 的引用。

请注意,这是与字节串代码不同的用例;字节串代码非常频繁地强制其参数,因此不太可能导致空间泄漏。最好将字节串代码解释为纯粹的优化,以避免指针取消引用。

关于haskell - 严格声明的意义何在?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6231821/

相关文章:

haskell - 你能在 Haskell 中为整个类而不是类型创建一个类的实例吗?

haskell - 无限自引用列表

haskell - cabal 安装 wx 缺少 C 库

haskell - 在 Haskell 中评估函数 a -> () 有什么规则?

data-structures - 序列与 LazyList

javascript - lodash 链式方法中的当前链

c++ - 在 C++ 中复制 Haskell 的返回类型重载(通过类型类)

haskell - 列出单子(monad)转换器

haskell - Haskell 中无限列表中项的惰性求值