显示中间状态时的映射

Dan*_*rro 6 haskell traversable

我需要一个执行此操作的函数:

>>> func (+1) [1,2,3]
[[2,2,3],[2,3,3],[2,3,4]]
Run Code Online (Sandbox Code Playgroud)

我的实际案例更复杂,但这个例子显示了问题的要点.主要的区别在于,实际上使用索引是不可行的.本List应该是一个TraversableFoldable.

编辑:这应该是功能的签名:

func :: Traversable t => (a -> a) -> t a -> [t a]
Run Code Online (Sandbox Code Playgroud)

更接近我真正想要的是相同的签名,traverse但无法弄清楚我必须使用的功能,以获得所需的结果.

func :: (Traversable t, Applicative f) :: (a -> f a) -> t a -> f (t a)
Run Code Online (Sandbox Code Playgroud)

K. *_*uhr 3

看起来 @Benjamin Hodgson 误读了你的问题,并认为你想要f应用于每个部分结果中的单个元素。因此,您最终认为他的方法不适用于您的问题,但我认为它适用。考虑以下变化:

import Control.Monad.State

indexed :: (Traversable t) => t a -> (t (Int, a), Int)
indexed t = runState (traverse addIndex t) 0
  where addIndex x = state (\k -> ((k, x), k+1))

scanMap :: (Traversable t) => (a -> a) -> t a -> [t a]
scanMap f t =
  let (ti, n) = indexed (fmap (\x -> (x, f x)) t)
      partial i = fmap (\(k, (x, y)) -> if k < i then y else x) ti
  in  map partial [1..n]
Run Code Online (Sandbox Code Playgroud)

这里,indexed在状态 monad 中进行操作,向可遍历对象的元素添加递增索引(并“免费”获取长度,无论这意味着什么):

> indexed ['a','b','c']
([(0,'a'),(1,'b'),(2,'c')],3)
Run Code Online (Sandbox Code Playgroud)

而且,正如 Ben 指出的那样,它也可以使用以下方式编写mapAccumL

indexed = swap . mapAccumL (\k x -> (k+1, (k, x))) 0
Run Code Online (Sandbox Code Playgroud)

然后,scanMap获取可遍历对象,将其映射到类似的前/后对结构,使用indexed索引它,并应用一系列partial函数,其中partial i为第一个i元素选择“afters”,为其余元素选择“befores”。

> scanMap (*2) [1,2,3]
[[2,2,3],[2,4,3],[2,4,6]]
Run Code Online (Sandbox Code Playgroud)

至于将其从列表推广到其他内容,我无法弄清楚您要对第二个签名做什么:

func :: (Traversable t, Applicative f) => (a -> f a) -> t a -> f (t a)
Run Code Online (Sandbox Code Playgroud)

因为如果你将其专门化为一个列表,你会得到:

func' :: (Traversable t) => (a -> [a]) -> t a -> [t a]
Run Code Online (Sandbox Code Playgroud)

并且根本不清楚您希望它在这里做什么。