Proposal: Subcomputations in arrow notation

Hello fellow Haskellers, this is a proposal to extend the arrow notation (-XArrows). I find myself writing the following very often: system :: Wire IO () String system = proc _ -> do botAddPeriod <- succ ^<< noise -< () botAddSpeed <- noise1 -< () botAddStart <- noise1 -< () botMsg <- event addBot -< (botAddPeriod, botAddSpeed, botAddStart) bots <- manager -< ((), maybe MgrNop id botMsg) let botStr = concatMap (printf "%8.2") . M.elems $ bots :: String identity -< printf "Bot positions: %s" botStr where addBot :: Wire IO (Double, Double, Double) (MgrMsg Int IO () Double) addBot = proc (addPeriod, addSpeed, addStart) -> do periodically -< addPeriod botId <- identifier -< () identity -< MgrAdd botId (constant addSpeed >>> integral addStart) The relevant part is the first paragraph of the first arrow computation: botAddPeriod <- succ ^<< noise -< () botAddSpeed <- noise1 -< () botAddStart <- noise1 -< () botMsg <- event addBot -< (botAddPeriod, botAddSpeed, botAddStart) This line should generate a message for the bot manager at random intervals. The actual event generator is in the second arrow computation 'addBot'. I would like to be able to write this more in line with the rest of the code. The following is possible: system :: Wire IO () String system = proc _ -> do botAddPeriod <- succ ^<< noise -< () botAddSpeed <- noise1 -< () botAddStart <- noise1 -< () botMsg <- event (proc (addPeriod, addSpeed, addStart) -> do periodically -< addPeriod botId <- identifier -< () identity -< MgrAdd botId (constant addSpeed >>> integral addStart)) -< (botAddPeriod, botAddSpeed, botAddStart) bots <- manager -< ((), maybe MgrNop id botMsg) let botStr = concatMap (printf "%8.2") . M.elems $ bots :: String identity -< printf "Bot positions: %s" botStr This is probably not a big improvement. It's more concise, but also harder to understand. My proposal is to add syntax to allow the following notation: system :: Wire IO () String system = proc _ -> do botAddPeriod <- succ ^<< noise -< () botAddSpeed <- noise1 -< () botAddStart <- noise1 -< () botMsg <- event $ do periodically -< addPeriod botId <- identifier -< () identity -< MgrAdd botId (constant addSpeed >>> integral addStart) bots <- manager -< ((), maybe MgrNop id botMsg) let botStr = concatMap (printf "%8.2") . M.elems $ bots :: String identity -< printf "Bot positions: %s" botStr Again the relevant part is the event generator in the middle. In this hypothetical syntax, the compiler would figure out from the inner computation, which variables from the outer scope are used and pass them automatically in an appropriate tuple. You wouldn't need any explicit passing anymore. If others like the idea, too, and there is nobody to implement it, then I would be willing to get in touch with the GHC code and implement this as a patch myself. What do you think? Greets, Ertugrul -- nightmare = unsafePerformIO (getWrongWife >>= sex) http://ertes.de/

I think this proposal makes so much sense that I'm surprised it didn't already work this way. - Jake

Ertugrul Soeylemez writes:
I find myself writing the following very often:
system :: Wire IO () String system = proc _ -> do botAddPeriod <- succ ^<< noise -< () botAddSpeed <- noise1 -< () botAddStart <- noise1 -< () botMsg <- event addBot -< (botAddPeriod, botAddSpeed, botAddStart)
bots <- manager -< ((), maybe MgrNop id botMsg) let botStr = concatMap (printf "%8.2") . M.elems $ bots :: String identity -< printf "Bot positions: %s" botStr
where addBot :: Wire IO (Double, Double, Double) (MgrMsg Int IO () Double) addBot = proc (addPeriod, addSpeed, addStart) -> do periodically -< addPeriod botId <- identifier -< () identity -< MgrAdd botId (constant addSpeed >>> integral addStart)
If addPeriod is supposed to be the same as botAddPeriod, etc, this should be equivalent: system :: Wire IO () String system = proc _ -> do addPeriod <- succ ^<< noise -< () addSpeed <- noise1 -< () addStart <- noise1 -< () botMsg <- (|event (do periodically -< addPeriod botId <- identifier -< () identity -< MgrAdd botId (constant addSpeed >>> integral addStart))|) bots <- manager -< ((), maybe MgrNop id botMsg) let botStr = concatMap (printf "%8.2") . M.elems $ bots :: String identity -< printf "Bot positions: %s" botStr See the GHC Arrow notation documentation for more about the banana brackets, which let you use user-defined control structures like event.

"Paterson, Ross"
See the GHC Arrow notation documentation for more about the banana brackets, which let you use user-defined control structures like event.
I have reread the documentation now. It seems that there are a lot of syntactic constructs, which I've missed. Particularly the banana bracket notation does exactly what I want. Thanks a lot! Greets, Ertugrul -- nightmare = unsafePerformIO (getWrongWife >>= sex) http://ertes.de/
participants (3)
-
Ertugrul Soeylemez
-
Jake McArthur
-
Paterson, Ross