【发布时间】:2017-01-29 02:26:28
【问题描述】:
在 Haskell 中,我们可以使用这个有用的习语从列表中获取索引元素的列表:
indexify :: (Num i) => [a] -> [(i,a)]
indexify = zip [0..]
但是,根据zip在GHC.List as of base-4.9.1.0中的实现,这不会完全执行列表融合,即这实际上不会生成列表[0..],但indexify的参数列表将是构建。
当然,有一个定义允许适当的列表融合:
indexify' :: (Num i) => [a] -> [(i,a)]
indexify' xs = build $ \c n ->
foldr (\x r !i -> (i,x) `c` r (i+1)) (const n) xs 0
我们需要import GHC.Prim (build) 来执行此操作吗?还是有其他简化为indexify' 的实现?
【问题讨论】:
-
indexify = let f !i x = (i + 1, (i, x)) in snd . mapAccumL f 0会起作用吗?我相信mapAccumL会被融合。 -
@Alec 我正准备将您的评论变成答案并接受它,但它不起作用。
mapAccumL定义为traverse = mapM,在“消费”方向融合(即使用foldr),但在“生产”方向不融合(即不使用build)。 -
啊。好点子。早该想到的。还是比
zip好一点。 :) -
另见ghc.haskell.org/trac/ghc/ticket/9495了解一些背景信息。
-
我认为this 应该或多或少地回答你的问题。 TL;DR:似乎没有更简单的实现,您可以从
GHC.Exts导入build。