我正在尝试“正确”地在 netwire 5 中实现一组动态电线。我已经阅读了电线问题的答案,并且我并不特别喜欢示例中的代码如何依赖于转换Event
为行为以在.stepWire
所以,我想通过Event
s 在动态集中添加和删除线,希望不利用Unsafe.Event
或等效的黑客。为简单起见,让我们删除删除部分,只需添加Wire
s 即可:
dynWireSet1 :: (Monad m, Monoid s)
=> Wire s e m (a, Event (Wire s e m a b)) [b]
每个事件都会向隐藏在其中的(最初为空的)列表(或其他集合)添加一条新线,它们都会运行,都获得 type 的输入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
来自Unsafe.Event
. 那是对的吗?我想避免Unsafe.Event
。
当我退后一步查看使用事件的建议方法时,我看到了一个看起来很有前途的函数:
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 开始:
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:
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
,我就准备好了!但这在一般情况下是不可能的。事实上,只要我做对fmap
了,WGen
就fmaps
超过了输出。无用。
现在,这是我的想法。让我们介绍一个 的新变体data Wire
,我暂时称它为,WCarry g st
因为它将以不同的数据类型携带其内部状态。它的转换函数将是类型
((a, c) -> m (b, c))
并且,给定初始状态,构造函数将生成这样的 Wire:
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
根据mkCarry
.
然后, fmap 实例看起来像这样:
fmap f (WCarry g st) = WCarry g (fmap f st)
它将改变“隐藏在内部”的状态对象,我们将能够krSwitch
在这种Wire
s 上有意义地使用函数,在不丢失先前值的情况下调整它们的内部状态。
这有意义吗?如果我想要做的事情以更简单的方式成为可能,请指教!如果我说的有道理,我该怎么做呢?是否可以使用 WCarry 本地扩展data Wire
定义,并扩展添加具有相应定义的有趣类实例?还有什么建议吗?
谢谢。