【问题标题】:How to force strict evaluation of a sequence of ByteString如何强制对 ByteString 序列进行严格评估
【发布时间】:2012-12-07 10:30:28
【问题描述】:

我有以下 Haskell 类型定义:

import Data.Sequence(Seq, length)
import Data.ByteString.UTF8(ByteString)

type StringSeq = Seq ByteString

我有StringSeq 类型的表达式,我想强制使用deepseq 进行严格评估。所以我需要定义NFData 的实例。我做了以下事情:

import Control.DeepSeq(NFData, deepseq)

instance NFData ByteString

instance NFData a => NFData (Seq a) where
  rnf s = rnf (length s)

所以我计算一个序列的长度来强制对序列本身进行评估。这似乎可行,但这是正确的实现吗?有更好的吗?计算一个序列的长度会不会引入太多的开销?

【问题讨论】:

  • 计算Seq 的长度不会有任何用处,因为Seq 已经是spine-strict。它肯定不是一个有效的NFData 实例,因为它甚至不会尝试强制Seq 的内容。此外,NFData 实际上不太可能是您想要的。你真正想做的是什么? deepseq 通常对于获得正确的严格行为(和性能)来说“太多,太迟了”。
  • 除了shachaf所说的,已经有一个NFData实例:instance NFData a => NFData (Seq a) where rnf (Seq xs) = rnf xs。 (arrh,仅在 7.6.1 附带的 containers 中,不适用于早期版本)
  • 但是,在将它们放入 Seq 之前,您所要做的就是 seqByteStrings。由于Seq 的脊椎严格,这确保了完整的评估。
  • @Daniel Fischer:但Seq 是函数的结果:返回Seq 的函数应用程序也必须进行评估。我必须检查seq这里是否足够,也许不是?

标签: haskell sequence strict bytestring


【解决方案1】:

你可以为严格定义一个 monad

data Strict a = Strict {fromStrict :: !a}
instance Monad Strict where
   return = Strict
   (Strict x) >>= f = f x

好的,我认为这实际上并不符合单子定律,但它已经足够接近了。使用它你可以定义一个函数

srnf = Strict . rnf 

这样

instance NFData a => NFData (Seq a) where
  rnf s = fromStrict $ (mapM srnf s) >> return ()

未经测试,但应该可以工作(它应该适用于所有Traversable 数据结构)。

【讨论】:

  • 我只是好奇,newtype Strict a = Strict { fromStrict :: a } 不也是严格的,性能稍微好一点吗?
  • newtype 并不严格。它只是不存在。关键是>>= 定义中的模式匹配在身份单子不强制评估时强制评估。你可以使用你定义的新类型,但你必须说Strict x >>= f = seq x $ f x
【解决方案2】:

计算长度不够,需要计算一个序列内容的范式。我建议您使用Control.Seq 中的seqFoldable,它允许您强制任何可折叠结构。然后你可以简单地调用

mySeq `using` seqFoldable rdeepseq

或定义

instance NFData a => NFData (Seq a) where
    rnf = seqFoldable rdeepseq

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-09-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-02-10
    相关资源
    最近更新 更多