As I’ve found myself repeatedly writing a bit of code that looked vaguely like this:
get :: SomeArrow String (Maybe Thing)
foo :: [Thing] -> FooThing
. . .
getAToZ :: SomeArrow () (Maybe FooThing)
getAToZ = proc () ->
do m_a <- get -< "a"
m_b <- get -< "b"
. . .
m_z <- get -< "z"
returnA -<
do a <- m_a
b <- m_b
. . .
z <- m_z
return $ foo [a,b . . . z]
It seemed that there would have to be a way to automate this. So I wrote this MaybeArrow (careful, I’m still using 6.8.2 so it’s the old arrows with ‘pure’.). I know that there is already an ErrorArrow. But ErrorArrow as far as I can see requires ArrowChoice, and I’m not doing that. In the MaybeArrow, if an earlier computation throws a Nothing, then later computations are still allowed to perform side effects, although their outputs are snuffed, which is the behavior I want.
I would appreciate any constructive feedback.
If you’re wondering the use case has to do with waiting on several separate pieces of information to arrive from a server and combining them into one output message.

hm, nice puzzle.
because of the missing ArrowChoice class,
you need sth like (“a”,(“b”,(“c”,(…))) inside the arrow. that means: a fixed length list.
but you need the fixed length only ‘inside’ the arrow, not in your sourcecode. so build it!
the idea is to build a chain of equal arrows, which can be simply combined… using lists instead of tuples. each link in that chain is a double list-/stream-transformer. each takes one item from the input list/stream and applies the computed output to the output list/stream. (chainlink)
that chain should process the list of inputs and should generate the list of outputs. (amap)
then on those outputs we have to test wether they all are Just cases… you use the Monad property, which is quite handy, but only if you know some library functions like sequence.
[my next reply shows the code]
well, reading your code above, i guess you still think a tiny bit ‘the imperative way’(tm) …so i advise to read Data.List and half of the paper “Functional Programming with Bananas, Lenses, Envelopes and Barbed Wire (1991)” (http://en.wikipedia.org/wiki/Catamorphism), that will blow most of that tedious imperative style away.
it’s about foldr and friends.
regards
- marc
(i’ve just read HWN-100, so this didn’t take 2 weeks.)
Ah, I see what you’re driving at. But I think there is a deficiency in the example, rather than the solution. The example ought to show a foo that takes some heterogeneous parameters.
hm… @moderator: please remove the code above. this is my 2nd try.
{-# LANGUAGE Arrows,TypeOperators,EmptyDataDecls #-} module MaybeArrow where --import Control.Category hiding ((.),id) import Control.Arrow data Thing data FooThing data SomeArrow b c --instance Control.Category.Category SomeArrow where instance Arrow SomeArrow where get :: SomeArrow String (Maybe Thing) get = undefined foo :: [Thing] -> FooThing foo = undefined -- chainlink :: ... -> ((a:ar,br) ~> (ar,b:br)) chainlink :: Arrow (~>) => (a ~> b) -> (([a],[b])~>([a],[b])) chainlink f = proc (a:ar,br) -> do b <- f -< a returnA -)) => (a ~> b) -> [a] -> (() ~> [b]) amap f as = proc x -> do (_,bs) >>) (arr id) $ replicate (length as) (chainlink f) ) -< (as,[]) returnA -< reverse bs getAToZ :: SomeArrow () (Maybe FooThing) getAToZ = amap get [[s]|s>> arr (fmap foo . sequence)hm… i don’t know how to submit code properly.
hey, you are online
what do you mean with heterogeneous parameters?
—–
chainlink :: Arrow (~>) => (a ~> b) -> (([a],[b])~>([a],[b]))
chainlink f = proc (a:ar,br) -> do
b <- f -< a
returnA -< (ar,b:br)
amap :: (Arrow (~>)) => (a ~> b) -> [a] -> (() ~> [b])
amap f as = proc x -> do
(_,bs) > > ) (arr id) $ replicate (length as) (chainlink f) ) -< (as,[])
returnA -< reverse bs
the three ‘>’ are the problem.
—-
amap :: (Arrow (~>)) => (a ~> b) -> [a] -> (() ~> [b])
amap f as = proc x -> do
(_,bs) ,>,>) (arr id) $ replicate (length as) (chainlink f) ) -< (as,[])
returnA -< reverse bs
argh!
in words:
(_,bs)
“arrow-left”
( foldr (
“GTGTGT”
) (arr id) $ replicate (length as) (chainlink f) ) -< (as,[])
Heterogenous parameters, in other words, what I really want is something like:
proc _ -> do m_a <- getA -< () m_b <- getB -< () m_c <- getC -< () returnA -< do a <- m_a b <- m_b c <- m_c return $ foo a b cAnd for some reason, I didn’t think clearly about that when I did the original example.
hm, k.
different getA/B/C, same monad.
as long as the example is short, this should work:
fmap (uncurry $ uncurry $ liftM3 foo) ((getA &&& getB) &&& getC) -< ()
i didn’t compile it, it’s 5:25 at night in germany.
goodn8.
- marc
Oh, that’s really annoying. I had to change a little bit of formatting with the new theme, and it got relisted on the planets.