Haskell Netwire:正确完成电线电线
Haskell Netwire: wires of wires done properly
我正在尝试在 netwire 5 "properly" 中实现一组动态线路。
我已经阅读了 问题的答案,我不太喜欢示例中的代码如何依赖 Event
转换为在 [=77= 上显示非空的行为] stepWire
.
的 正好是一次执行
所以,我想通过 Event
s 在动态集中添加和删除连线,并且希望不要利用 Unsafe.Event
或等效的 hackery。为了简单起见,让我们删除删除部分,只需要添加 Wire
s:
dynWireSet1 :: (Monad m, Monoid s)
=> Wire s e m (a, Event (Wire s e m a b)) [b]
每个事件都会向隐藏在内部的(最初为空)列表(或其他集合)中添加一条新线,并且它们都 运行,都获得类型 a
的输入,并且将他们的输出收集到列表中。
运行ning 部分相对简单,示例可通过 google 搜索,例如:
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)
上面的例子忽略了事件。我怀疑这是不可能的
在转换函数中使用事件,而不是通过
来自 Unsafe.Event
的 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
现在,如果我从简化的 运行电线开始会怎么样:
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
over WGen
只是 fmaps
over the output,如果我没弄错的话。没用。
现在,这是我的想法。让我们介绍一下 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
类型。根据 mkCarry
.
重新表述 runWires
很容易
然后,fmap 实例看起来像这样:
fmap f (WCarry g st) = WCarry g (fmap f st)
它将改变 "hidden inside" 状态对象,我们将能够在这种 Wire
上有意义地使用 krSwitch
函数,在不丢失的情况下调整它们的内部状态之前的值。
这有意义吗?如果我想做的事情可以用更简单的方式实现,请指教!如果我说的有道理,我怎么能去做呢?是否可以使用 WCarry 在本地扩展 data Wire
定义,并扩展添加具有相应定义的有趣 Class 实例?还有其他建议吗?
谢谢。
我在使用 Netwire 时遇到了完全相同的问题,所以我认为回答这个问题会很有用。我同意使用(安全的)事件是正确的方法。不过我不喜欢加上WCarry
,感觉不太直观。
您实际上非常接近答案。制作 addWire
的关键在于您不想 'modify' 旧电线。您想要的是创建一条添加了给定子线输出的新线,所以这可能就是您要找的:
addWire w ws = fmap (uncurry (:)) (w &&& ws)
这根电线为两根电线供电,然后加入输出。希望对您有所帮助!
我正在尝试在 netwire 5 "properly" 中实现一组动态线路。
我已经阅读了 Event
转换为在 [=77= 上显示非空的行为] stepWire
.
所以,我想通过 Event
s 在动态集中添加和删除连线,并且希望不要利用 Unsafe.Event
或等效的 hackery。为了简单起见,让我们删除删除部分,只需要添加 Wire
s:
dynWireSet1 :: (Monad m, Monoid s)
=> Wire s e m (a, Event (Wire s e m a b)) [b]
每个事件都会向隐藏在内部的(最初为空)列表(或其他集合)中添加一条新线,并且它们都 运行,都获得类型 a
的输入,并且将他们的输出收集到列表中。
运行ning 部分相对简单,示例可通过 google 搜索,例如:
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)
上面的例子忽略了事件。我怀疑这是不可能的
在转换函数中使用事件,而不是通过
来自 Unsafe.Event
的 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
现在,如果我从简化的 运行电线开始会怎么样:
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
over WGen
只是 fmaps
over the output,如果我没弄错的话。没用。
现在,这是我的想法。让我们介绍一下 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
类型。根据 mkCarry
.
runWires
很容易
然后,fmap 实例看起来像这样:
fmap f (WCarry g st) = WCarry g (fmap f st)
它将改变 "hidden inside" 状态对象,我们将能够在这种 Wire
上有意义地使用 krSwitch
函数,在不丢失的情况下调整它们的内部状态之前的值。
这有意义吗?如果我想做的事情可以用更简单的方式实现,请指教!如果我说的有道理,我怎么能去做呢?是否可以使用 WCarry 在本地扩展 data Wire
定义,并扩展添加具有相应定义的有趣 Class 实例?还有其他建议吗?
谢谢。
我在使用 Netwire 时遇到了完全相同的问题,所以我认为回答这个问题会很有用。我同意使用(安全的)事件是正确的方法。不过我不喜欢加上WCarry
,感觉不太直观。
您实际上非常接近答案。制作 addWire
的关键在于您不想 'modify' 旧电线。您想要的是创建一条添加了给定子线输出的新线,所以这可能就是您要找的:
addWire w ws = fmap (uncurry (:)) (w &&& ws)
这根电线为两根电线供电,然后加入输出。希望对您有所帮助!