5

Traversable从某种意义上说,它的结构具有“路径”(可以对应于列表)的容器类,可以在不分解结构的情况下修改其上的元素。因此

zipTrav :: Traversable t => t a -> [b] -> Maybe (t (a,b))
zipTrav = evalStateT . traverse zp
 where zp a = do
           bs <- get
           case bs of
              [] -> lift Nothing
              (b:bs') -> put bs' >> return (a,b)

但是,这种列表状态遍历似乎有点骇人听闻,并且可能不是最有效的方法。我想会有一个标准功能可以完成上述或更一般的任务,但我不知道它会是什么。

4

1 回答 1

5

mapAccumL/呢mapAccumR

tzipWith :: Traversable t => (a -> b -> c) -> [a] -> t b -> Maybe (t c)
tzipWith f xs = sequenceA . snd . mapAccumL pair xs
    where pair [] y = ([], Nothing)
          pair (x:xs) y = (xs, Just (f x y))

tzip :: Traversable t => [a] -> t b -> Maybe (t (a, b))
tzip = tzipWith (,)

ghci> tzip [1..] [4,5,6]
Just [(1,4),(2,5),(3,6)]

ghci> tzip [1,2] [4,5,6]
Nothing

关于效率问题 -在引擎盖下mapAccum函数使用状态单子,所以我真正所做的就是在高阶函数中捕获代码的命令部分。我不希望这段代码比你的代码执行得更好。但我认为你不能比State单子(或ST)做得更好,只给出Traversable t.

于 2017-01-07T16:09:01.393 回答