1

我想使用类型的线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''')
4

1 回答 1

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将处理输入foo3 秒,然后bar处理 3 秒,然后交替返回。在这种情况下,many pulseFooBar没有任何意义。由于您在任何给定时间步中多次执行,pulseFooBar将不再每三秒切换一次,并且取决于时间步之间的输入和时间。

于 2014-08-21T22:29:22.287 回答