One way to think about arrows is to do something like a factory diagram. You would be right if your SF were just (->) . Go ahead and try; you should get:
Prelude Control.Arrow> mapA (0 :) [[1,2,3],[4,5],[6],[7,8],[9,10,11],[12,13,14,15]] [[0,1,2,3],[0,4,5],[0,6],[0,7,8],[0,9,10,11],[0,12,13,14,15]]
However, the machines in the factory can do something more complicated than just sending the converted -> how it works to their converted input. Your SF machines "take" a and "pull" a b , but they are supported by the function [a] -> [b] , which allows you to pass stream a , and then they can do something more complex than -> .
Thus, the delay 0 machine takes a stream of numbers and adds 0 to it, easy peasy, "delays" the source stream with one "time step" if you want to think about it.
Similarly, a1 &&& a2 will have to feed its input stream to both machines, and when they both matter, they can “pin” them together. He uses his sub machines [b] -> [c] and [b] -> [d] to create [b] -> [(c, d)] , after all.
Machine a1 ||| a2 a1 ||| a2 more complicated: it takes the similar machines [b] -> [d] and [c] -> [d] and uses them to form [Either bc] -> [d] . If it looked completely self-evident, look again! We did not have Either [b] [c] , which would be quite simple (and with which -> deals above), but rather [Either bc] . The obvious solution for this is:
- Take the left sub-list, put it on the left computer
- Take the right sub-list, put it on the right machine
- Returns the received
[d] in some complex alternating order.
What order? The easiest way is to return to the original list, and when you see the left one, print d from the left list of machines; whenever you see Right, give d from the right list.
With all this background, we go to mapA :
mapA f = arr listcase >>> arr (const []) ||| (f *** mapA f >>> arr (uncurry (:)))
For SF , the listcase will accept an incoming list stream and create an Either () (x, [x]) stream, depending on whether this stream is empty. In the first pass through the list, none of the entries in your runSF empty, so each list is a Right branch that emits one valid value.
So, we have [Right (1, [2,3]), Right (4, [5]), Right (6, []), ...] , which is smoothed and divided into two lists: [1, 4, 6, ...] and [[2,3], [5], [], ...] .
This first list is fed into the delay function, so it is added to 0 . The second list gets recursively in mapA f , so the prefixes [2, 5] are also delayed; etc.
In the end, when you combine them, you will find that each level of nesting in the lists is delayed, so that the first emitted list is [0, 0, 0], and the second is [1, 2].