Control.Category, что означает >>> и <<<?

Я следую этот блог, чтобы написать простой http-сервер в haskell,

Использование >>> мне не понятно. Что делает этот фрагмент кода?

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

Similary на эта ссылка, я вижу <<<

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

Что делают <<< и >>>? (Документ hackage очень краток и не может получить много от него.)

Ответы

Ответ 1

Как сообщит вам Hackage и/или Hoogle,

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

Заметим, что последнее фактически совпадает с

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

или в форме Prelude, специализированной для категории функций Hask,

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

Итак, <<< и >>> просто составляют функции или, в более общем смысле, морфизмы/стрелки.

<<< состоит в том же направлении, что и знакомый ., а >>> переворачивает аргументы так, чтобы "данные текли слева направо".


Теперь, что означает композиция стрелки для категорий, отличных от Hask, зависит, конечно, от категории. Kleisli IO - это простой пример: скажем, мы имеем чистую функцию

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

Как я уже сказал, это также можно записать

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

Теперь, если вы хотите добавить примитивные записи ввода-вывода (например, на императивном языке), вы можете ввести

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

С этим вы можете определить

pipe' :: Double -|> String

точно так же, как и раньше, т.е.

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

Но теперь вы получите промежуточные результаты, напечатанные как побочный эффект.