Search code examples
haskellarrow-abstraction

Chaining arrows of types `a b [c]` and `a c d`


I have an arrow which outputs a list of values (a b [c]) and another arrow which accepts a single value of that type (a c d). What I need basically is a way to chain them or uplift the second arrow to a [c] [d].


Solution

  • You cannot do this with just Arrow type class. Lifting a b c into a [b] [c] requires choice between [] and (:) case. Luckily for us, ArrowChoice offers exactly this operation.

    mapA :: ArrowChoice a => a b c -> a [b] [c]
    mapA f = proc list -> case list of
        []   -> returnA -< []
        x:xs -> do
            y  <- f      -< x
            ys <- mapA f -< xs
            returnA      -< y:ys
    

    Your function is then simply:

    chain :: ArrowChoice a => a b [c] -> a c d -> a b [d]
    chain f g = f >>> mapA g
    

    Without proc notation, we would need a function that translates list constructors into Either:

    listCase :: [a] -> Either () (a, [a])
    listCase []     = Left ()
    listCase (x:xs) = Right (x,xs)
    
    mapA f = arr listCase >>>
        arr (const []) ||| (f *** mapA f >>> arr (uncurry (:)))