Reactive Banana的mapAccum功能如何运作?

时间:2012-09-08 01:54:07

标签: haskell reactive-banana

我已经在Stack Overflow上查看了一些问题的答案,试图在使用Reactive Banana库时找到问题的解决方案。所有答案都使用了一些 magic ,使用了'mapAccum',这是我无法理解的。查看API文档,我发现“accumEaccumB的高效组合”。这不是很有帮助。

似乎这个函数可以用来比较两个连续事件时Behavior的值,这是我想要做的。但我不清楚如何做到这一点。

mapAccum究竟是如何运作的?

3 个答案:

答案 0 :(得分:4)

mapAccum函数与标准Data.List模块中的mapAccumL函数非常相似,因此名称。 Hackage的文档还包含source code of mapAccum的链接。与type signature一起,希望有足够的信息来确定这个函数的工作原理。

然后,我可以改进文档。 :-)但我还不清楚如何做到这一点,不能粘贴源代码。结果的第二部分易于通过以下等式描述

snd . mapAccum acc = accumB acc . fmap (. snd)

但第一部分没有这么好的等式。

我可以用文字写一个描述:

  

函数mapAccum通过应用类型acc的第二个参数中包含的函数来累积类型Event t (acc -> (x,acc))的状态。该函数返回一个事件,其出现值为x,并返回跟踪累积状态acc的行为。换句话说,这是一台Mealy机器或州自动机。

但我不确定这些词是否真的有帮助。

答案 1 :(得分:4)

请注意

mapAccum :: acc -> Event t (acc -> (x, acc)) -> (Event t x, Behavior t acc)

所以它需要一个初始值:: acc来累积,一个事件产生一个函数 在产生输出值::x时更新累计值。 (通常,您通过<$>部分应用某些功能来制作此类事件。) 因此,您会收到一个新事件,只要它们出现并且包含行为,就会触发x值 你目前的累积价值。

如果您有某个活动并且想要制作相关的行为和活动,请使用mapAccum

例如,在your other question的问题域中,假设您有一个不正常的事件eTime :: Event t Int,并且您希望计算eDeltaTime :: Event t Int的差异和bTimeAgain :: Behaviour t Int 对于当前使用的时间:

type Time = Int
type DeltaTime = Time 

getDelta :: Time -> Time -> (DeltaTime,Time)
getDelta new old = (new-old,new)

我本可以写getDelta new = \old -> (new-old,new)来使下一步更清楚:

deltaMaker :: Event t (Time -> (DeltaTime,Time))
deltaMaker = getDelta <$> eTime

(eDeltaT,bTimeAgain) = mapAccum 0 $ deltaMaker

在这种情况下,bTimeAgain将是与eTime中的事件具有相同值的行为。有时候是这样的 因为我的getDelta函数直接将neweTime传递到acc值。 (如果我自己想要bTimeAgain,我会使用stepper :: a -> Event t a -> Behaviour t a。) 如果我不需要bTimeAgain,我可以写(eDeltaT,_) = mapAccum 0 $ deltaMaker

答案 2 :(得分:1)

注意:我正在使用答案,因此我可以编写格式化代码

以下是我记录该功能的尝试:


mapAccum ::                  acc -- Initial Accumulation Value
  ->   Event t (acc -> (x, acc)) -- Event stream that of functions that use the previous
                                 -- accumulation value to:
                                 -- a) produce a new resulting event (x) and,
                                 -- b) updates the accumulated value (acc)
  -> (Event t x, Behavior t acc) -- fst) a stream of events from of a) above
                                 -- snd) a behavior holding the accumulated values b) above

此函数类似于mapAccumL模块中的Data.List函数。它是accumEaccumB的有效组合。除其他外,生成的Behavior对于保存事件流的值(x)可能需要的先前事件的历史记录非常有用。

示例:计算过去5个事件的滚动平均值

rolingAverage :: forall t. Frameworks t => Event t Double -> Event t Double
rolingAverage inputStream = outputStream
  where
    funct x xs = (sum role / 5, role) where role = (x:init xs)
    functEvent = funct <$> inputStream -- NB: curries the first parameter in funct
    (outputStream,_) = mapAccum [0,0,0,0,0] functEvent