1

I would like use a wire of type Wire s e m a b to handle multiple inputs. The intended semantics would be

  • If the input list is [] do nothing and return an empty list
  • If the input list is a:as step the wire with input a, recursively step the resulting wire with input as, and then collect the results into a list

Is this a sensible thing to do? Is my implementation sensible? Inhibitions are completely ignored here, which seems strange. What is the right way to create wires that handle "multiple events at once" in 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''')
Tom Ellis
  • 8,007
  • 21
  • 45
  • I don't really think this is a good idea. The way I understood it, wires should only be stepped once per instant, otherwise you're violating continuous time semantics. This would work fine with pure wires (but if you're using this for pure wires you should map just with a function instead of a wire), but what about stateful ones? – Cubic Jun 11 '14 at 10:13
  • I don't understand the objection. I can *already* write wires that do this by hand. I'm just asking if this combinator is a sensible way to abstract the process. – Tom Ellis Jun 11 '14 at 10:53

1 Answers1

1

Your question is kind of difficult to answer, since abstractions are really only useful to the applications that use them. Ignoring inhibition is not a problem per se, but you do lose a lot of the functionality from things like the Alternative typeclass.

Suppose you had a wire that converts keypresses into actions and inhibits when no key is pressed:

inputWire :: Wire s e m Key Action

You could create a wire that falls back to a default action if the first wire inhibits:

defaultAction :: Wire s e m a Action
defaultAction = ... whatever ...

actionWire :: Wire s e m Key Action
actionWire = inputWire <|> defaultAction

If you wanted to create something that handled multiple inputs, ideally you'd like to do something like:

actionWire :: Wire s e m [Key] [Action]
actionWire = (many inputWire) <|> (defaultAction >>> (arr (: [])))

... but this wouldn't really work with your implementation. You could add a guard to check for nonempty lists from many but you're making something much more verbose than it needs to be.


The objection that @Cubic mentioned about the lack of continuous time semantics, however, is a problem. Suppose you had a wire that switches based on a certain amount of time:

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

In this example, pulseFooBar will handle the input as foo for three seconds and then as bar for three seconds and then alternate back. In this context, many pulseFooBar doesn't make any sense. Since you step multiple times in any given timestep, pulseFooBar will no longer switch every three seconds, and becomes dependent on the input and time between timesteps.

Mokosha
  • 2,567
  • 14
  • 30