паду ли я, стрелой пронзеный
иль мимо пролетит она...

(ария Ленского)

arrow-программирование

у нас есть функции двух видов:

  • из типа a в тип b
  • из типа a в тип "возможно b"
  • и желание соединять их между собой ...

    что такое стрелки? а это - функторы, но функторы не простые, а функторы как раз для морфизмов. то есть именно для функций. а нам того и нужно ведь - нам нужно любые функции лифтить куда угодно. а как это сделать?

    рецепт известен - нужен общий интерфейс и его реализации в каждом конкретном случае. а интерфейс как раз простой - и называется он "стрелки": он нам лифтит любую функцию в любую категорию - нужно только реализовать саму механику этого лифтинга - то есть функцию arr:

        class Category A => Arrow A
           arr (b -> c) :: A b c 
    
    для некоего A (которое может быть чем угодно) которое символизирует собой стрелку (на самом деле категорию назначения для лифтинга)

    нам еще предлагается реализовать функцию >>> которая просто композит между собой две залифтинные стрелки (для функций - (.), для монад - (>>=), для аппликативов - (<*>) и т.д.)

    для монад стрелки получаются автоматически и называются "стрелками Клейсли", но смысл в том, что мы можем вообще абстрагироваться даже от монад - стрелки они вобще могут быть чем угодно. но в случае монад они уже есть - заранее готовые


    import Control.Arrow
    import Control.Monad
    
    ------------
    
    f1 :: Int -> Bool 
    f1 = \x -> if x > 10 then True else False 
    
    m1 :: Int -> Maybe Bool 
    m1 = \x -> Just $ case x of 0 -> True  ;  _ -> False
    
    f2 :: Bool -> Int
    f2 = \x -> if x then 12 else 0
    
    m2 :: Bool -> Maybe Int 
    m2 = \x -> Just $ if x then 100 else 13 
    
    -----------
    
    a1 :: Kleisli Maybe Int Bool 
    a1 = arr f1
    
    a2 :: Kleisli Maybe Bool Int 
    a2 = arr f2
    
    
    k1 :: Kleisli Maybe Int Bool
    k1 = Kleisli m1
    
    k2 :: Kleisli Maybe Bool Int 
    k2 = Kleisli m2
    
    -------------------------
    
    k1a2 = runKleisli $ k1 >>> a2
    
    k1k2 = runKleisli $ k1 >>> k2 
    
    k2k1 = runKleisli $ k2 >>> k1 
    
    k2a1 = runKleisli $ k2 >>> a1 
    
    a1a2 = runKleisli $ a1 >>> a2 
    
    a1k2 = runKleisli $ a1 >>> k2
    
    a2a1 = runKleisli $ a2 >>> a1 
    
    a2k1 = runKleisli $ a2 >>> k1
    

    Лепота! - молвил царь
    и ответили все - Лепота!