16

I am following this blog, to write a simple http server in haskell,

Usage of >>> is not clear to me. What does this code snippet do?

handleHttpConnection r c = runKleisli
    (receiveRequest >>> handleRequest r >>> handleResponse) c >>
    close c

Similary on this link, i am seeing <<<

let h =     arr (++ "!")
          <<< arr foo
          <<< Kleisli bar
          <<< arr id

What does <<< and >>> do? (Hackage document is very concise and couldn't get much out of it.)

duplode
  • 33,731
  • 7
  • 79
  • 150
  • 1
    That blog has a [link](https://wiki.haskell.org/Arrow_tutorial#Kleisli_Arrows) to an article about Kleisli Arrows that seems useful. I believe these two operators represent some kind of function composition (for Arrows which are functions). For other kinds of Arrows, I'm not sure, as arrows are a little strange to me. – jpaugh Jul 05 '15 at 08:36

1 Answers1

21

As Hackage and/or Hoogle will tell you,

(>>>) :: Category k => a`k`b  -> b`k`c  -> a`k`c
(<<<) :: Category k => b`k`c  -> a`k`b  -> a`k`c

Observe that the latter is actually the same as

(.)   :: Category k => b`k`c  -> a`k`b  -> a`k`c

or, in its Prelude form, specialised to the Hask category of functions,

(.)   ::               (b->c) -> (a->b) -> (a->c)

So, <<< and >>> simply compose functions, or more generally morphisms/arrows.

<<< composes in the same direction as the familiar ., while >>> flips the arguments so that “data flows from left to right”.


Now, what arrow composition means, for categories other than Hask, depends of course on the category. Kleisli IO is an easy to understand example: say we have a pure function

pipe :: Double -> String
pipe = show . sqrt . (+2) . abs

As I said, this can also be written

pipe = abs >>> (+2) >>> sqrt >>> show

Now, if you want to add primitive IO logging (like you might in an imperative language), you can introduce

type (-|>) = Kleisli IO

abs', add2', sqrt' :: Num a => a -|> a
show' :: Show a => a -|> String

abs'  = Kleisli $ \x -> do putStrLn ("Absolute of "++show x++"...")
                           return $ abs x
add2' = Kleisli $ \x -> do putStrLn ("Add 2 to "++show x++"...")
                           return $ x + 2
sqrt' = Kleisli $ \x -> do putStrLn ("Square root of "++show x++"...")
                           return $ sqrt x
show' = Kleisli $ \x -> do putStrLn ("Show "++show x++"...")
                           return $ show x

With that, you can define

pipe' :: Double -|> String

in exactly the same way as before, i.e.

pipe' = abs' >>> add2' >>> sqrt' >>> show'

But you'll now get the intermediate results printed out as a side-effect.

leftaroundabout
  • 117,950
  • 5
  • 174
  • 319
  • that is a beautiful example... thanks... why would someone do `show . sqrt . (+2) . abs` instead of `show $ sqrt $ (+2) $ abs n`. i know, dot `.` is all about some function composition , but does it solve any problem that `$` doesn't solve? –  Jul 05 '15 at 09:42
  • 3
    @MadhavanKumar: well, this is in fact an excellent example for what `$` doesn't solve: it can't be generalised to work in arbitrary categories. ([Some categories have a generalisation of `$`, but most don't – including `Kleisli`](http://stackoverflow.com/questions/31118949/generalising-like-control-category-generalises/31120454#31120454).) Apart from that, point-free style is often more concise, can be somewhat easier refactored, and doesn't require you to introduce a variable name... however, these aren't always advantages; sometimes point-free is harder to understand (“pointless code”). – leftaroundabout Jul 05 '15 at 11:04
  • 1
    Then, are `<=<` and `>=>` also special cases of `<<<` and `>>>` that work for monads? – imz -- Ivan Zakharyaschev Jul 05 '15 at 12:00
  • I have written code similar to your example, but using `<*>` and `<$>` in the applicative which is a composition of of the applicative for function (composition) and for the effect I'm interested in (logging in your example), i.e., Compose (a->) (Reader ..). Perhaps you are cleaner – imz -- Ivan Zakharyaschev Jul 05 '15 at 12:02
  • 2
    @imz--IvanZakharyaschev: Yes, I think so, only that `>=>` don't need that `Kleisli` newtype wrapper around the monadic function. – Bergi Jul 05 '15 at 12:37