Haskell Netwire:线缆正确完成

时间:2015-10-14 15:33:32

标签: haskell netwire

我正在尝试在netwire 5"中正确地实现一组动态电线"。 我已经阅读了wires of wires问题的答案,而且我并不特别喜欢示例中的代码依赖于Event转换为行为以显示非空的问题只有stepWire的一次执行

因此,我希望通过Event添加和删除动态集中的连线,并希望无需点击Unsafe.Event或等效的hackery。为简单起见,我们放弃删除部分,只需添加Wire s即可:

dynWireSet1 :: (Monad m, Monoid s)
            => Wire s e m (a, Event (Wire s e m a b)) [b]

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

运行部件相对容易,有可谷歌示例,例如:

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)

上面的例子忽略了事件。我怀疑这是不可能的 在转换函数中使用事件,而不是使用 来自event的{​​{1}}函数。那是对的吗?一世 我想避免Unsafe.Event

当我退后一步看看建议的使用事件的方式时,我看到了一个 功能看起来很有希望:

Unsafe.Event

现在,如果我从简化的runWires开始怎么办?

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

并使dynWireSet成为krSwitch:

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)

我快到了!现在,如果我只能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超过(:)并将新电汇插入runWires2,我就会全部设定!但在一般情况下,这是不可能的。事实上,newwires超过fmapWGen输出,如果我做对了。无用的。

现在,这是我的想法。让我们介绍fmaps的新变体,我暂时将其称为data Wire,因为它将以不同的数据类型传递其内部状态。它的转换函数将是

类型
WCarry g st

并且,在初始状态下,构造函数将生成如下的Wire:

((a, c) -> m (b, c))

仅在结果电汇中引入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开始,很容易重新构建runWires

然后,fmap实例看起来像这样:

mkCarry

它将改变隐藏的内部&#34;状态对象,我们可以在这种fmap f (WCarry g st) = WCarry g (fmap f st) s上有意义地使用krSwitch函数来调整其内部状态而不会丢失之前的值。

这有意义吗?如果我想以更简单的方式做,我们建议!如果我所说的是有道理的,我怎么能去做呢?是否可以使用WCarry在本地扩展Wire定义,并使用相应的定义扩展添加有趣的Class实例?还有其他建议吗?

感谢。

1 个答案:

答案 0 :(得分:2)

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

你实际上非常接近答案。使addWire依赖的关键在于你不想“修改”旧线。你想要的是创建一个添加了给定子线的输出的新线,所以这可能是你想要的:

addWire w ws = fmap (uncurry (:)) (w &&& ws)

此导线连接两根导线,然后连接输出。希望它有所帮助!