4

FRP の感触をつかもうとして netwire パッケージをいじっていますが、簡単な質問があります。

次の単純なワイヤーから始めて、5 秒ごとに (約) イベントを発行できます。

myWire :: (Monad m, HasTime t s) => Wire s () m a Float
myWire = timeF

myWire' :: (Monad m, HasTime t s) => Wire s () m a Int
myWire' = fmap round myWire

myEvent :: (Monad m, HasTime t s) => Wire s () m a (Event Int)
myEvent = periodic 5 . myWire'

これは非常に素晴らしく簡単ですが、次にやりたいことは、生成された各イベントをワイヤーにマップして、更新を監視できるようにすることです。次のようなアキュムレータ関数があります。

eventList :: (Monad m, HasTime t s) 
            => Wire s () m a (Event [Wire s () m a Int])
eventList = accumE go [] . myEvent
  where go soFar x = f x : soFar
        f x = for 10 . pure x --> pure 0

次に、イベントのトリガーが開始されるまで禁止する新しいワイヤを導入しeventListます。次のようにします。

myList :: (Monad m, HasTime t s) => Wire s () m a [Wire s () m a Int]
myList = asSoonAs . eventList

だから私はイベントからワイヤのリストを含むワイヤに行きました。最後に、これらの各ワイヤをステップ実行して結果のリストを生成するワイヤを導入します。

myNums :: (Monad m, HasTime t s) => Wire s () m [Wire s () m a Int] [Int]
myNums = mkGen $ \dt wires -> do
  stepped <- mapM (\w -> stepWire w dt $ Right undefined) wires
  let alive = [ (r, w) | (Right r, w) <- stepped ]
  return (Right (map fst alive), myNums)

myNumList :: (Monad m, HasTime t s) => Wire s () m a [Int]
myNumList = myNums . myList

最後に、すべてをテストするためのメイン ルーチンがあります。

main = testWire clockSession_ myNumList

私が期待しているのは、リスト内の各要素が 10 秒間の作成時間を示し、その後、要素がゼロを表示する、成長するリストです。私が代わりに得ているのは、静的値のリストの増加です。たとえば、いくつかの手順を実行すると、次のようになります。

[0]
[5, 0]
[10, 5, 0]
[15, 10, 0, 0]

等々。私が実際に見ているのは、

[0]
[5, 0]
[10, 5, 0]
[15, 10, 5, 0]

したがって、アキュムレータ関数が機能していることはわかっています。作成されたすべてのイベントがワイヤに変換されています。しかし、私が見ていないのは、これらのワイヤが時間の経過とともに異なる値を放出していることです。私のステートメントfor 10 . pure x --> pure 0は、時間が経過した後、それらを 0 を発行するように切り替える必要があります。

私はまだFRPに慣れていないので、何か重要なことを根本的に誤解している可能性があります(おそらくそうです).

4

2 に答える 2

2

問題は、イベントから生成されたワイヤが永続的でないことです。type の指定された値は、Wire s e m a b実際には、 type の値からtype の値を生成する関数のインスタンスです。Haskell は不変の値を使用するため、ワイヤをステップ実行するには、結果のワイヤで何かを行う必要があります。そうしないと、同じ入力に対して同じ出力が得られます。からの結果を見てみましょう:bastepWiremyList

Event 1: [for 10 . pure 0 --> pure 0]
Event 2: [for 10 . pure 5 --> pure 0, for 10 . pure 0 --> pure 0]
Event 3: [for 10 . pure 10 --> pure 0, for 10 . pure 5 --> pure 0, for 10 . pure 0 --> pure 0]
... etc

これらのワイヤーのそれぞれを踏む[.., 10, 5, 0]と、ワイヤーの元の値を再利用しているため、毎回取得するだけですfor 10 . pure x --> pure 0。の署名を見てくださいstepWire:

stepWire :: Monad m => Wire s e m a b -> s -> Either e a -> m (Either e b, Wire s e m a b)

これは、次のようなステートメントの場合、

(result, w') <- stepWire w dt (Right underfined)

... はw'、次に を呼び出す必要があるときに使用する必要がありますstepWire。これは、次のインスタンスでの動作であるためです。ワイヤを生成するワイヤがある場合は、生成されたワイヤをどこかにオフロードして、個別に処理できるようにする必要があります。

必要な動作を提供する (私が信じている) プログラムについては、このコードを参照してください。

$ ghc -o test test.hs
[1 of 1] Compiling Main             ( test.hs, test.o )
Linking test ...
$ ./test
[0]
[5,0]
[10,5,0]
[15,10,0,0]
[20,15,0,0,0]
...
于 2015-03-08T00:54:21.757 に答える