我正在尝试在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
超过fmap
仅WGen
输出,如果我做对了。无用的。
现在,这是我的想法。让我们介绍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实例?还有其他建议吗?
感谢。
答案 0 :(得分:2)
我使用Netwire并遇到了完全相同的问题,所以我认为回答这个问题会很有用。我同意使用(安全)事件是正确的方法。但是我不喜欢添加WCarry
,它似乎不太直观。
你实际上非常接近答案。使addWire
依赖的关键在于你不想“修改”旧线。你想要的是创建一个添加了给定子线的输出的新线,所以这可能是你想要的:
addWire w ws = fmap (uncurry (:)) (w &&& ws)
此导线连接两根导线,然后连接输出。希望它有所帮助!