6

ここで、Reactive Banana ライブラリの使用に関する問題の解決策を見つけようとして、Stack Overflow に関する質問に対する多くの回答を見てきました。すべての答えは、私がよく理解できない「mapAccum」を使用した魔法を使用しています。accumEAPI ドキュメントを見ると、「との効率的な組み合わせ」しか見つかりませんaccumB。これはあまり役に立ちません。

この関数はBehavior、私がやりたいことである 2 つの連続したイベントの時点での値を比較するために使用できるようです。しかし、それを機能させる方法がわかりません。

正確にはどのように機能しmapAccumますか?

4

3 に答える 3

4

この関数は、標準の Data.List モジュールmapAccumの関数に非常に似ているため、この名前が付けられています。mapAccumLHackage のドキュメントには、 のソース コードmapAccumへのリンクも含まれています。型シグネチャと併せて、この関数がどのように機能するかを理解するのに十分な情報であることが期待されます。

繰り返しになりますが、ドキュメントを改善することができました。:-) しかし、ソースコードを貼り付ける以外の方法については、完全に明確ではありません。結果の 2 番目の部分は、次の式で簡単に説明できます。

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

しかし、最初の部分にはそのような素晴らしい方程式はありません。

言葉で説明を書くことができます:

この関数は、 typeの 2 番目の引数に含まれる関数を適用することにより、mapAccumtype の状態を累積します。この関数は、発生が値であるイベントと、蓄積された状態を追跡する動作を返します。別の言い方をすれば、これはミーリー マシン、またはステート オートマトンです。accEvent t (acc -> (x,acc))xacc

しかし、これらの言葉が実際に役立つかどうかはわかりません。

于 2012-09-08T11:25:49.947 に答える
4

注意してください

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

そのため、蓄積する初期値:: accと、出力値を生成しながらその蓄積値を更新する関数を生成するイベントが必要です::x。(通常、このようなイベントは、 を介して一部の関数を部分的に適用することで作成し<$>ます。) その結果、値がx現れるたびに値を起動する新しいイベントと、現在の累積値を含む動作が得られます。

mapAccumイベントがあり、関連する動作とイベントを作成する場合に使用します。

たとえば、他の質問の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関数が変更されずに値からそのまま通過するためnewに発生します。(単独で使用したい場合は、 を使用していたでしょう。) が必要ない場合は、 と書くだけで済みます。eTimeaccbTimeAgainstepper :: a -> Event t a -> Behaviour t abTimeAgain(eDeltaT,_) = mapAccum 0 $ deltaMaker

于 2012-09-08T17:13:17.723 に答える
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ます。accumEとの効率的な組み合わせですaccumB。結果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  
于 2012-09-10T02:27:26.367 に答える