Haskell Netwire:电线 [英] Haskell Netwire: wires of wires

查看:127
本文介绍了Haskell Netwire:电线的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



从下面的简单线索开始,我用一个简单的线每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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆