首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Haskell Netwire:电线

Haskell Netwire:电线
EN

Stack Overflow用户
提问于 2015-03-07 19:17:17
回答 2查看 398关注 0票数 4

我正在玩网络包,试图得到一个感觉玻璃钢,我有一个快速的问题。

从以下简单的连线开始,我可以每5秒发出一个事件(大约)

代码语言:javascript
复制
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'

这是相当好和直接,但我想要做的下一步是映射每个事件产生的电线,然后我可以观看更新。我有一个累加器函数,如下所示:

代码语言:javascript
复制
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开始触发事件,如下所示:

代码语言:javascript
复制
myList :: (Monad m, HasTime t s) => Wire s () m a [Wire s () m a Int]
myList = asSoonAs . eventList

所以我已经从事件转到了一条包含电线列表的电线。最后,我介绍了一条导线,用于对每条电线进行分步,并产生一个结果列表:

代码语言:javascript
复制
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

最后,我有我的主要例程来测试这一切:

代码语言:javascript
复制
main = testWire clockSession_ myNumList

我希望看到的是一个不断增长的列表,列表中的每个元素都将显示其创建时间为10秒,之后元素将显示为零。相反,我得到的是一个越来越多的静态值列表。例如,经过几步之后,我希望看到的是

代码语言:javascript
复制
[0]
[5, 0]
[10, 5, 0]
[15, 10, 0, 0]

诸若此类。我真正看到的是

代码语言:javascript
复制
[0]
[5, 0]
[10, 5, 0]
[15, 10, 5, 0]

所以我知道我的累加器功能是工作的:创建的每一个事件都被转换成一条线路。但我没有看到的是,随着时间的推移,这些电线发出了不同的值。经过一段时间后,我的语句for 10 . pure x --> pure 0应该将它们切换到释放0。

我对玻璃钢还不熟悉,所以我可能从根本上误解了它的一些重要内容(可能就是这种情况)。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-03-08 00:54:21

问题是从事件中产生的连线不是持久的。Wire s e m a b类型的给定值实际上是一个函数的实例,该实例从类型a的值生成b类型的值。由于Haskell使用不可变的值,为了步进连接,您必须对来自stepWire的结果线执行一些操作,否则您将得到相同输入的相同输出。看看myList的结果

代码语言:javascript
复制
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的签名

代码语言:javascript
复制
stepWire :: Monad m => Wire s e m a b -> s -> Either e a -> m (Either e b, Wire s e m a b)

这意味着对于诸如

代码语言:javascript
复制
(result, w') <- stepWire w dt (Right underfined)

..。下次需要调用w'时,应该使用stepWire,因为它是下一个实例的行为。如果您有一条产生电线的电线,那么您需要将所产生的电线卸载到某个地方,以便它们可以单独处理。

对于一个程序(我相信)给你你想要的行为,请参考这段代码

代码语言:javascript
复制
$ 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]
...
票数 2
EN

Stack Overflow用户

发布于 2015-03-08 01:48:38

作为莫科沙建议,我们可以从以前的事件中保留我们已经知道的连线的状态,并从最新的事件中引入连线。例如,如果我们已经不知道任何事件,并且得到一个包含一条线的列表,那么我们应该使用新的连接。

代码语言:javascript
复制
      [] -- we already know about
w0' : [] -- we got as input
w0' : [] -- what we should keep

如果我们已经知道一根或一根电线,并发现更多的电线,我们需要保留我们已经知道的电线,并添加我们刚刚发现的新电线。

代码语言:javascript
复制
            w2  : w1  : w0  : [] -- we already know about
w4' : w3' : w2' : w1' : w0' : [] -- we got as input
w4' : w3' : w2  : w1  : w0  : [] -- what we should keep

这更容易从列表的前端定义。第一个参数将是结果的前缀。如果还剩下第二个参数,我们将把它们添加到列表的末尾。

代码语言:javascript
复制
makePrefixOf :: [a] -> [a] -> [a]
makePrefixOf [] ys = ys
makePrefixOf xs [] = xs
makePrefixOf (x:xs) (_:ys) = x:makePrefixOf xs ys

通过反转输入和输出,我们可以为列表的后端定义相同的内容。第一个参数将是结果的后缀,如果有任何额外的第二个纪念碑,它们将添加到列表的前面。

代码语言:javascript
复制
makeSuffixOf :: [a] -> [a] -> [a]
makeSuffixOf xs ys = reverse $ makePrefixOf (reverse xs) (reverse ys)

现在,我们可以实现myNums,跟踪我们已经拥有状态的oldWires

代码语言:javascript
复制
myNums :: (Monad m, HasTime t s) => Wire s () m [Wire s () m a b] [b]
myNums = go []
  where
    go oldWires = mkGen $ \dt newWires -> do
        let wires = makeSuffixOf oldWires newWires
        stepped <- mapM (\w -> stepWire w dt $ Right undefined) wires
        let alive = [ (r, w) | (Right r, w) <- stepped ]
        return (Right (map fst alive), go (map snd alive))

如果我们想变得迂腐,我们应该使用一个Maybe线列表,这样当电线不再活动时,我们可以留下一个Nothing来代替它,这样电线列表仍然匹配。如果我们这样做,即使用一个巧妙的状态表示,我们也会在电线失效时泄漏空间。他们最初的定义仍将徘徊在eventList正在积累的列表中。

这提供了所需的输出

代码语言:javascript
复制
            [ 0]
         [ 5, 0]
      [10, 5, 0]
   [15,10, 0, 0]
[20,15, 0, 0, 0]
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/28918915

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档