Haskell 如何强制严格计算ByteString序列
我有以下Haskell类型定义:Haskell 如何强制严格计算ByteString序列,haskell,sequence,strict,bytestring,Haskell,Sequence,Strict,Bytestring,我有以下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 By
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)
所以我计算一个序列的长度来强制计算序列本身。这似乎可行,但这是正确的实现方式吗?有更好的吗?计算一个序列的长度会带来太多的开销吗?为了严格起见,可以定义一个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 ()
未经测试,但应该可以工作(它应该适用于所有可遍历的数据结构) 计算长度是不够的,您需要计算序列内容的标准形式。我建议您使用from
Control.Seq
,它允许您强制任何可折叠结构。然后你可以简单地打电话
mySeq `using` seqFoldable rdeepseq
或定义
instance NFData a => NFData (Seq a) where
rnf = seqFoldable rdeepseq
计算
Seq
的长度没有任何用处,因为Seq
已经很严格了。它当然不是一个有效的NFData
实例,因为它甚至没有试图强制执行Seq
的内容。而且,NFData
实际上不太可能是您想要的;你到底想干什么deepseq
通常对于获得正确的严格行为(和性能)来说“太多、太晚了”。除了shachaf所说的,已经有一个NFData
实例:实例NFData a=>NFData(Seq a),其中rnf(Seq xs)=rnf xs
。(啊,仅在7.6.1附带的容器中,不适用于早期版本),但是,在将seq
放入seq
之前,您所要做的就是ByteString
s。由于Seq
的脊柱狭窄,这确保了完整的评估。@Daniel Fischer:但是Seq
是函数的结果:返回Seq
的函数应用程序也必须进行评估。我必须检查seq
在这里是否足够,也许不够?我只是好奇,newtype Strict a=Strict{fromStrict::a}
也很严格,性能稍好一些吗?newtype
不严格。它根本不存在。关键是>>=
定义中的模式匹配在标识单子不匹配时强制求值。您可以使用您定义的新类型,但必须说Strict x>=f=seq x$f x
。