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

Haskell Netwire:电线做得很好
EN

Stack Overflow用户
提问于 2015-10-14 15:33:31
回答 1查看 224关注 0票数 4

我正试图在网络5中实现一套动态的电线“正确”。我已经阅读了wires of wires问题的答案,并且我并不特别喜欢示例中的代码如何依赖于Event转换成一种行为,在stepWire的一次执行中显示非空。

因此,我想通过Event添加和删除动态集合中的电线,并且希望不使用Unsafe.Event或类似的黑客。为了简单起见,让我们删除删除部分,只需添加Wire

代码语言:javascript
复制
dynWireSet1 :: (Monad m, Monoid s)
            => Wire s e m (a, Event (Wire s e m a b)) [b]

每个事件都会向隐藏在内部的(最初为空的)列表(或其他一组)添加一条新的连线,它们都会运行,都会获得a类型的输入,并将它们的输出收集到一个列表中。

运行部分相对容易,有可搜索的示例,例如:

代码语言:javascript
复制
dynWireSet1 = runWires1 []
runWires1 :: (Monad m, Monoid s)
          => [Wire s e m a b]
          -> Wire s e m (a, Event (Wire s e m a b)) [b]
runWires1 wires = mkGen $ \session (input, event) -> do
  stepped <- mapM (\w -> stepWire w session (Right input)) wires
  let (outputs, newwires) = unzip stepped
  return (sequence outputs, runWires1 newwires)

上面的示例忽略事件。我怀疑,除了使用来自eventUnsafe.Event函数之外,不可能在转换函数中使用该事件。对吗?我想避免Unsafe.Event

当我回过头来看一下使用事件的建议方法时,我看到一个看起来非常有前途的函数:

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

现在,如果我从简化的runWires开始呢:

代码语言:javascript
复制
runWires2 :: (Monad m, Monoid s)
          => [Wire s e m a b]
          -> Wire s e m a [b]
runWires2 wires = mkGen $ \session input -> do
  stepped <- mapM (\w -> stepWire w session (Right input)) wires
  let (outputs, newwires) = unzip stepped
  return (sequence outputs, runWires2 newwires)

并使dynWireSet成为一个krSwitch:

代码语言:javascript
复制
dynWireSet2 :: (Monad m, Monoid s)
            => Wire s e m (a, Event (Wire s e m a b)) [b]
dynWireSet2 = krSwitch (runWires2 []) . second (mkSF_ (fmap addWire))
addWire :: Wire s e m a b -> Wire s e m a [b] -> Wire s e m a [b]
addWire = undefined

我快到了!现在,如果我能够fmap一个(:) and runWires2并将新的电线插入到newwires中,我就准备好了!但这在一般情况下是不可能的。事实上,如果我做得对的话,fmapWGen上只是对输出的fmaps。没用。

现在,这是我的主意。让我们介绍一个新的data Wire变体,我暂时称它为WCarry g st,因为它将以不同的数据类型携带其内部状态。它的转换函数将是

代码语言:javascript
复制
((a, c) -> m (b, c))

并且,在初始状态下,构造函数将生成如下所示的导线:

代码语言:javascript
复制
mkCarry :: Monad m => ((a, c) -> m (b, c)) -> c -> Wire s e m a b
mkCarry transfun state = mkGenN $ \input -> do
  (output, newstate) <- transfun (input, state)
  return (Right output, mkCarry transfun newstate)

只在结果线中引入WCarry类型而不是WGen类型。用runWiresmkCarry进行重构是很容易的。

然后,fmap实例将如下所示:

代码语言:javascript
复制
fmap f (WCarry g st) = WCarry g (fmap f st)

它将更改“隐藏在内部”状态对象,我们将能够在这类Wire上有意义地使用Wire函数来调整它们的内部状态,而不会丢失以前的值。

这有道理吗?如果我想做的事情能够以更简单的方式进行,请提出建议!如果我说的是有意义的话,我该怎么做呢?是否可以用data Wire在本地扩展WCarry定义,并用相应的定义扩展有趣的类实例?还有其他建议吗?

谢谢。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-12-13 17:15:04

我正在使用Netwire,我遇到了同样的问题,所以我认为回答这个问题是有用的。我同意使用(安全)事件是正确的方法。然而,我不喜欢添加WCarry,这似乎不太直观。

你其实非常接近答案。要使addWire生效的关键在于,您不希望“修改”旧线路。您想要的是创建一个新的电线,并添加给定子线路的输出,所以这可能就是您所要寻找的:

代码语言:javascript
复制
addWire w ws = fmap (uncurry (:)) (w &&& ws)

这条线既给两根电线送去,又把输出连接起来。希望能帮上忙!

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/33129623

复制
相关文章

相似问题

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