A newbie question about Arrows.

Ross Paterson ross@soi.city.ac.uk
Fri, 10 Jan 2003 12:18:39 +0000


On Thu, Jan 09, 2003 at 10:30:45AM -0600, Shawn P. Garbett wrote:
> On Monday 06 January 2003 04:02 am, Nicolas Oury wrote:
> > I think for example to event-driven arrows : we could make a pair of
> > inputs without mixing the "event happened" information.
> 
> Here's one that's been baffling me: What about the case where you have two 
> arrows you want to combine. Suppose that each of these arrows are a stream 
> processor, which process the type Either.
> 
> SP (Either a b) (Either a b)
> 
> Now combing these with the sequencing operator is straightforward. The output 
> of the first SP becomes the input of the second.
> 
> (>>>) :: SP i o -> SP i o -> SP i o
> 
> Or in a routing diagram
> 
> In >- SP1 --> SP2 --> Out
> 
> But what if you wanted to mix up the routing of Left and Right from the
> Either above?
> 
> In(Left) -> SP1(Left)
> In(Right) -> SP2(Right)
> SP1(Right) -> SP2(Left)
> SP2(Left) -> SP1(Right)
> SP1(Left) -> Out(Left)
> SP2(Right) -> Out(Right)

Here's a method that's generalizable, if not elegant.

We need a feedback combinator that feeds the Right output channel back
to the input (this is a trivial variant of the loop combinators in the
Fudgets library):

        fixSP :: SP a (Either b a) -> SP a b

For convenience we define

        output = Left   -- produce some output from the network
        send = Right    -- route to a stream processor 

and define a datatype for the components:

        data Input a b c d e f
                = In (Either a b)
                | SP1 (Either c d)
                | SP2 (Either e f)

Obviously the need for a new datatype is a drawback, but it lets us name
the components' input streams.

Now your example can be coded in arrow notation as

        combine sp1 sp2 = arr In >>> fixSP (proc z -> case z of
                In (Left v) ->
                        returnA -< send (SP1 (Left v))
                In (Right v) ->
                        returnA -< send (SP2 (Right v))
                SP1 x -> do
                        out <- sp1 -< x
                        returnA -< case out of
                                Left v -> output (Left v)
                                Right v -> send (SP2 (Left v))
                SP2 x -> do
                        out <- sp2 -< x
                        returnA -< case out of
                                Left v -> send (SP1 (Right v))
                                Right v -> output (Right v))

Your example had only 1-1 connexions, but the generalization isn't hard.