我如何在Haskell中使用镜头来复制Python的枚举?

Ale*_*x R 4 haskell haskell-lens

Python 列表中的枚举可以写成zip [0..].我查看了Control.Lens.Traversal和Control.Lens.Indexed,但我无法弄清楚如何使用镜头将其概括为任何合理的容器(我犹豫说"Traversable").

我猜itraverse或是itraverseOf关键.

cch*_*ers 8

如果您使用的容器是FunctorWithIndex当时的实例,您只需使用imap (,):

> imap (,) "abc"
[(0,'a'),(1,'b'),(2,'c')]
Run Code Online (Sandbox Code Playgroud)

但如果索引不是位置,则不起作用:

> let m = Map.fromList [('a', "foo"), ('b', "bar"), ('c', "foobar")])
> imap (,) m
fromList [('a',('a',"foo")),('b',('b',"bar")),('c',('c',"foobar"))]
Run Code Online (Sandbox Code Playgroud)

相反,您可以使用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"))]
Run Code Online (Sandbox Code Playgroud)


bhe*_*ilr 6

一种解决方案是使用Statemonad 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)
Run Code Online (Sandbox Code Playgroud)