Python上的枚举可以写成zip [0..]
。我看了Control.Lens.Traversal和Control.Lens.Indexed,但我不知道如何使用镜头将其推广到任何合理的容器(我不愿说“可遍历”)。
我猜itraverse
或itraverseOf
是关键。
发布于 2015-03-18 07:42:20
如果使用的容器是FunctorWithIndex
的实例,那么只需使用imap (,)
> imap (,) "abc"
[(0,'a'),(1,'b'),(2,'c')]
但是,如果指数不是这个位置,这是行不通的:
> let m = Map.fromList [('a', "foo"), ('b', "bar"), ('c', "foobar")])
> imap (,) m
fromList [('a',('a',"foo")),('b',('b',"bar")),('c',('c',"foobar"))]
相反,您可以使用traversed
,它是一个索引遍历,其中索引是元素显示的顺序。这可以用于任何Traversable
。不要使用imap
,而是使用iover traversed
(这与imapOf
相同,但已被废弃):
> iover traversed (,) "abc"
[(0,'a'),(1,'b'),(2,'c')]
> iover traversed (,) m
fromList [('a',(0,"foo")),('b',(1,"bar")),('c',(2,"foobar"))]
发布于 2015-03-18 07:00:35
一种解决方案是将State
monad与traverse
一起使用,因为它也是Applicative
。
enumerate :: (Integral n, Traversable t) => t a -> t (n, a)
enumerate t = evalState (traverse go t) 0
where
go a = do
i <- get
modify (+1)
return (i, a)
发布于 2015-03-18 07:41:52
您忽略了Applicative
在itraverse
上的上下文。你需要一些东西来配合它。但有些东西可能会很无聊,比如Identity
。
imap f = runIdentity . itraverse (\i a -> return (f i a))
然后你得到了你想要的:
> imap (,) [1,2,3]
[(0,1),(1,2),(2,3)]
https://stackoverflow.com/questions/29125149
复制