我想使用Wire s e m a b
类型的电线来处理多个输入。预期的语义是
[]
则不执行任何操作并返回空列表a:as
,则输入带有输入a
的连接,以输入as
递归步骤生成的连线,然后将结果收集到列表中这是明智的做法吗?我的实施是否明智?这里完全忽略了抑制,这似乎很奇怪。什么是在netwire中创建处理“多个事件”的电线的正确方法?
many :: (Monoid s, Monad m) => Wire s e m a b -> Wire s e m [a] [b]
many w = mkGen (\s as -> do
(bs, w') <- go s w as
return (Right bs, many w'))
where go _ w' [] = return ([], w')
go s w' (a:as) = do
(e, w'') <- stepWire w' s (Right a)
(bs, w''') <- go s w'' as
let b = case e of Right r -> [r]
Left _ -> []
return (b ++ bs, w''')
答案 0 :(得分:1)
您的问题很难回答,因为抽象实际上只对使用它们的应用程序有用。忽略禁止不是本身的问题,但是你确实从Alternative
类型类中失去了许多功能。
假设您有一根电线将按键转换为动作,并在没有按下按键时禁止按下:
inputWire :: Wire s e m Key Action
如果第一根电线禁止,您可以创建一条回退到默认操作的电线:
defaultAction :: Wire s e m a Action
defaultAction = ... whatever ...
actionWire :: Wire s e m Key Action
actionWire = inputWire <|> defaultAction
如果你想创建一些处理多个输入的东西,理想情况下你想做的事情是:
actionWire :: Wire s e m [Key] [Action]
actionWire = (many inputWire) <|> (defaultAction >>> (arr (: [])))
...但这不适用于您的实施。您可以添加一个警卫来检查来自many
的非空列表,但是您正在制作比它需要的更冗长的内容。
@Cubic提到缺乏连续时间语义的反对意见,然而, 是一个问题。假设您有一根基于一定时间切换的电线:
foo :: Wire s e m a b
bar :: Wire s e m a b
-- This wire pulses the action of a key to be move or moveFast
pulseFooBar :: Wire s e m a b
pulseFooBar = (foo >>> (for 3)) -->
(bar >>> (for 3)) -->
pulseFooBar
在此示例中,pulseFooBar
将输入为foo
三秒钟,然后为bar
三秒钟,然后交替返回。在这种情况下,many pulseFooBar
没有任何意义。由于您在任何给定的时间步长中多次步进,pulseFooBar
将不再每三秒切换一次,并且取决于时间步之间的输入和时间。