这是收集网络输入的合理方式吗?

时间:2014-06-11 08:05:53

标签: haskell frp netwire

我想使用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''')

1 个答案:

答案 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将不再每三秒切换一次,并且取决于时间步之间的输入和时间。