我做了一个应该模仿"流"的类型。这基本上是没有记忆的列表。
data Stream a = forall s. Stream (s -> Maybe (a, s)) s
基本上,流有两个元素。状态s
,以及获取状态的函数,并返回类型为a
的元素和新状态。
我希望能够对流执行操作,因此我已导入Data.Foldable
并在其上定义了流:
import Data.Foldable
instance Foldable Stream where
foldr k z (Stream sf s) = go (sf s)
where
go Nothing = z
go (Just (e, ns)) = e `k` go (sf ns)
为了测试我的流的速度,我已经定义了以下功能:
mysum = foldl' (+) 0
现在我们可以比较普通列表的速度和我的流类型:
x1 = [1..n]
x2 = Stream (\s -> if (s == n + 1) then Nothing else Just (s, s + 1)) 1
--main = print $ mysum x1
--main = print $ mysum x2
我的流速度大约是列表速度的一半(完整代码here)。
此外,这是一个最好的情况,没有列表或流:
bestcase :: Int
bestcase = go 1 0 where
go i c = if i == n then c + i else go (i+1) (c+i)
这比列表和流版本快得多。
所以我有两个问题:
bestcase
。答案 0 :(得分:4)
根据您给出的折叠器定义foldl'
来自Foldable
的{{1}}。默认的实现是辉煌的,令人惊讶的好
foldl' :: (b -> a -> b) -> b -> t a -> b
foldl' f z0 xs = foldr f' id xs z0
where f' x k z = k $! f z x
但是foldl'是你的特色;幸运的是,Foldable
类包含foldl'
作为方法,因此您只需将其添加到您的实例即可。
foldl' op acc0 (Stream sf s0) = loop s0 acc0
where
loop !s !acc = case sf s of
Nothing -> acc
Just (a,s') -> loop s' (op acc a)
对我而言,这似乎与bestcase
几乎相同
请注意,这是一个标准情况,我们需要在累加器上使用严格注释。对于某些想法,您可以查看vector
包对类似类型https://hackage.haskell.org/package/vector-0.10.12.2/docs/src/Data-Vector-Fusion-Stream.html的处理;或者在文本库https://github.com/bos/text/blob/master/Data/Text/Internal/Fusion的隐藏“融合”模块中。