What do the special brackets (| … |) desugar into?
Pregunta
I've read the arrow notation documentation page, but it's not entirely clear to me what the "pipe brackets" used under "7.10.3. Defining your own control structures" desugar into.
Given the example in the above document
proc x -> do
y <- f -< x+1
(|untilA (increment -< x+y) (within 0.5 -< x)|)
What's the equivalent code without using arrow notation?
Solución
The (| ... |)
brackets (usually called banana brackets) are for applying a function that operates on commands, inside proc notation. They are used to disambiguate a function that operates on commands (called an 'operator') from a normal command. Binary infix operators are special cased, so you don't need to write (| (&&&) x y |)
.
As for the desugaring, they're GHC's version of the form keyword from the Arrows paper.
form is defined as follows:
proc p -> form e c1 c2 ... cn
=
e (proc p -> c1) (proc p -> c2) ... (proc p -> cn)
So, proc x -> (|untilA (increment -< x+y) (within 0.5 -< x)|)
would become:
untilA (proc x -> increment -< x+y) (proc x -> within 0.5 -< x)
If you want to desugar this entirely so there is no arrow syntax left, it would become:
untilA (arr (\x -> x+y) >>> increment) (arr (\x -> x) >>> within 0.5)
Otros consejos
This is a very rough and intuitive answer and I'm not certain it's correct but it feels like it is. If you have
proc a -> do
a1 <- command1 <- ...
...
an <- commandn <- ...
(| structure (block1 -< expression1[a, a1, ..., an])
...
(blockm -< expressionm[a, a1, ..., an])
|)
then (|
|)
is a way of feeding in all the <-
-bound variables in scope into the block
s, i.e. it becomes (equivalent to)
proc a -> do
a1 <- command1 <- ...
...
an <- commandn <- ...
structure (proc (a, a1, ..., an) -> do
block1 -< expression1[a, a1, ..., an])
...
(proc (a, a1, ..., an) -> do
blockm -< expressionm[a, a1, ..., an])
-< (a, a1, ..., an)
I only grasped this when reading Oliver Charles's docs for antijoins in Rel8. I still find it rather mind-bending.