Haskell Netwire:电线 [英] Haskell Netwire: wires of wires
问题描述
从下面的简单线索开始,我用一个简单的线每5秒发出一个事件(大约)
myWire ::(Monad m,HasTime ts)=> Wire s()m a Float
myWire = timeF
myWire'::(Monad m,HasTime t s)=> Wires()m a Int
myWire'= fmap round myWire
myEvent ::(Monad m,HasTime t s)=> Wire s()m a(Event Int)
myEvent = periodic 5。 myWire'
这是相当不错且直接的,但我想接下来要做的是映射每个事件制作成电线,然后我可以观看更新。我有一个累加器函数,如下所示:
pre $ eventList ::(Monad m,HasTime t s)
=> Wire s()m a(Event [Wire s()m a Int])
eventList = accumE go []。 myEvent
where soFar x = f x:soFar
f x = for 10。纯x - >纯0
然后引入一条新线路,直到 eventList
开始触发事件,如下所示:
myList ::(Monad m,HasTime ts)=> Wire s()m a [Wire s()m Int]
myList = asSoonAs。 eventList
所以我已经从事件转移到一个包含电线列表的电线。最后,我介绍一个电线来分析每条电线并产生一个结果列表:
myNums ::(Monad m, HasTime ts)=> Wire s()m [Wire s()m a Int] [Int]
myNums = mkGen $ \dt wires - >
步骤< - mapM(\ w - > stepWire w dt $ Right undefined)wires
let alive = [(r,w)| (Right r,w)< - steps]
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]
<等等。我真正看到的是
$ b $ pre $ $ $ $ $ $ $ $ $ $ $ $ $ $ 5,0]
[15,10,5,0]
所以我知道我的累加器功能正在工作:创建的每个事件正在转换为电线。但是我没有看到这些导线随着时间的推移发出不同的值。我的发言为10。纯x - >纯粹的0
应该在时间结束后切换到0。
我对FRP仍然很陌生,所以我可能从根本上误解一些重要的东西(可能是这种情况)。
问题是由事件产生的连线并不是持久的。一个给定值的类型 Wire semab
实际上是一个函数的实例,它产生一个类型为 b
从类型 a
的值。由于Haskell使用不可变的值,所以为了实现连线,您必须使用从 stepWire
生成的连线执行某些操作,否则对于相同的输入会得到相同的输出。查看 myList
的结果:
事件1: 10。纯0 - >纯0]
事件2:[为10。纯5 - >纯0,10。纯0 - >纯0]
事件3:[为10。纯10 - >纯0,10。纯5 - >纯0,10。纯0 - >纯0]
...等
当你每走这些线时,因为你将的原始值重用为10,所以每次只得到
线。查看 [..,10,5,0]
。纯x - >纯0 stepWire
的签名:
stepWire :: Monad m = > Wires e m a b - > s - >或者e a - > m(eb,Wire semab)
这意味着对于像
(result,w')< - stepWire w dt(右下)
...下次需要调用 stepWire时,应使用
,因为它是下一个时刻的行为。如果你有一根导线产生导线,那么你需要将产生的导线卸下,以便它们可以分别处理。 w'
对于一个程序(我相信)给出了你想要的行为,请参阅此代码。
$ ghc -o test test.hs
[1的1]编译Main(test.hs,test.o)
链接测试。 ..
$ ./test
[0]
[5,0]
[10,5,0]
[15,10,0,0]
[20,15,0,0,0]
...
I'm playing around with the netwire package trying to get a feel for FRP, and I have a quick question.
Starting with the following simple wires, I'm able to emit an event every 5 seconds (approx)
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'
This is pretty nice and straight forward, but what I want to do next is map each event produced to a wire, that I can then watch update. I have an accumulator function like the following:
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
I then introduce a new wire that will inhibit until the eventList
starts triggering events, like so:
myList :: (Monad m, HasTime t s) => Wire s () m a [Wire s () m a Int]
myList = asSoonAs . eventList
So I've gone from events to a wire containing a list of wires. Finally, I introduce a wire to step each of these wires and produce a list of results:
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
And finally, I have my main routine to test it all out:
main = testWire clockSession_ myNumList
What I expect to see is a growing list, where each element in the list will show it's creation time for 10 seconds, after which the element will show a zero. What I'm getting instead is a growing list of static values. For example, what I expect to see after a few steps is
[0]
[5, 0]
[10, 5, 0]
[15, 10, 0, 0]
and so on. What I'm actually seeing is
[0]
[5, 0]
[10, 5, 0]
[15, 10, 5, 0]
So I know my accumulator function is working: every event created is being converted into a wire. But what I'm not seeing are these wires emitting different values over time. My statement for 10 . pure x --> pure 0
should be switching them over to emitting 0 after the time has elapsed.
I am still new to FRP, so I may be fundamentally misunderstanding something important about it (probably the case.)
The problem is that the wires generated from the events are not persistent. A given value of type Wire s e m a b
is actually an instance in time of a function that produces a value of type b
from a value of type a
. Since Haskell uses immutable values, in order to step wires, you have to do something with the resulting wire from stepWire
otherwise you get the same output for the same input. Take a look at the results from myList
:
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
When you step each of these wires, you're only going to get [.., 10, 5, 0]
every time because you're reusing the original value of the for 10 . pure x --> pure 0
wire. Look at the signature for stepWire
:
stepWire :: Monad m => Wire s e m a b -> s -> Either e a -> m (Either e b, Wire s e m a b)
This means that for a statement such as
(result, w') <- stepWire w dt (Right underfined)
... the w'
should be used the next time you need to call stepWire
, because it is the behavior at the next instance in time. If you have a wire that produces wires, then you need to offload the produced wires somewhere so that they can be processed separately.
For a program that (I believe) gives you the behavior you want, please refer to this code.
$ 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]
...
这篇关于Haskell Netwire:电线的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!