
Ross Paterson
I'd like to hear from anyone who's using arrow notation as supported by GHC, because I'm planning a couple of changes to parts of it.
I'm making heavy use of arrow notation, so I'd like to propose a set of small improvements, not only syntactical. ## Ignored input values Many computations ignore their input value. You can recognize them by their type: If the input type is fully polymorphic and the output type is unrelated, the computation cannot use its input value. In that case it would make sense to just pass whatever is the cheapest thing you could pass without requiring me to spell it out: comp1 :: Arr a Int comp2 :: Arr a Double Before: proc x1 -> do x2 <- comp1 -< x1 x3 <- comp2 -< x2 id -< (x2, x3) After: proc _ -> do x1 <- comp1 x2 <- comp2 id -< (x1, x2) Then the arrow notation compiler could just pass whatever is most convenient at that spot. In this case it would just compose with '&&&': comp1 &&& comp2 ## returnA We don't need it anymore, and it has quite a stupid definition. Get rid of it in favor of 'id'. ## Operators I often need to mix regular arguments with computation arguments in banana notation: let f c = f' x y c z (| f (comp -< v) |) Since parentheses are required for computation arguments you could relax the syntax to allow regular arguments in simple cases as well: (| f' x y (comp -< v) z |) ## PreArrow All sensible arrows form a family of functors: instance (Arrow a) => Functor (a b) where fmap f = (arr f .) But they do more: Every arrow is a profunctor as defined in the 'profunctors' package: instance (Arrow a) => Profunctor a where lmap f = (. arr f) rmap = fmap That's just what you called PreArrow, so there is no need to reinvent the wheel. Get Profunctor into base. ## Applicative One of the main bottlenecks of arrows is the heavy tuple handling, but most (if not all) arrows form a family of applicative functors. I noticed a huge speedup by moving from arrow style to applicative style where possible: liftA2 (+) (lmap f c) (fmap g d) is often much faster than: arr (uncurry (+)) . (c . arr f &&& arr g . d) Besides being more readable it sometimes improved the performance of my code by an order of magnitude. So perhaps check to see if the category forms an applicative functor. If it does, you can get along without Arrow entirely. In fact I propose to generalize all the Arrow* classes to Category* classes. The ultimate goal is to get rid of arrows. We don't really need them anymore. I'd rather like to see SHE's idiom brackets in Haskell and use a more lightweight syntax for stuff like ArrowChoice and ArrowLoop (or CategoryChoice and CategoryLoop), although I don't yet know what it would look like. Greets, Ertugrul -- Not to be or to be and (not to be or to be and (not to be or to be and (not to be or to be and ... that is the list monad.