2015-07-05 30 views
16

Seguo this blog, a scrivere un semplice server http in Haskell,Control.Category, cosa significa >>> e <<< significa?

Uso di >>> non è chiaro per me. Che cosa fa questo frammento di codice?

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

Analogamente il this link, sto vedendo <<<

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

Cosa <<< e >>> fare? (Hackage document è molto conciso e non poteva ottenere molto di fuori di esso.)

+1

Quel blog ha un [collegamento] (https://wiki.haskell.org/Arrow_tutorial#Kleisli_Arrows) a un articolo sulle frecce di Kleisli che sembra utile. Credo che questi due operatori rappresentino una sorta di composizione di funzioni (per le frecce che sono funzioni). Per altri tipi di frecce, non ne sono sicuro, poiché le frecce sono un po 'strane per me. – jpaugh

risposta

20

Come Hackage e/o Hoogle vi dirà,

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

Si osservi che quest'ultimo è in realtà lo stesso di

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

o, nella sua forma Prelude, specializzato per il Hask categoria di funzioni,

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

Quindi, <<< e >>> compongono semplicemente funzioni, o più in generale morfismi/frecce.

<<< compone nella stessa direzione del familiare ., mentre >>> ribalta gli argomenti in modo che i dati “ cassa da sinistra a destra ”.


Ora, che cosa freccia composizione significa, per le categorie diverse da Hask, dipende ovviamente dalla categoria. Kleisli IO è un facile da capire esempio: dire che abbiamo una funzione di pura

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

Come ho detto, questo può anche essere scritta

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

Ora, se si desidera aggiungere primitiva IO legname (come te potrebbe in un linguaggio imperativo), è possibile introdurre

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 

Con questo, è possibile definire

pipe' :: Double -|> String 

in esattamente allo stesso modo di prima, vale a dire

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

Ma avrete ora ottenere i risultati intermedi stampati come un effetto collaterale.

+0

questo è un bellissimo esempio ... grazie ... perché qualcuno dovrebbe "mostrare". sqrt. (+2). abs' invece di 'mostra $ sqrt $ (+2) $ abs n'. lo so, dot' .' è tutto incentrato sulla composizione di alcune funzioni, ma risolve qualsiasi problema che '$' non risolva? –

+2

@MadhavanKumar: beh, questo è in realtà un eccellente esempio di ciò che '$' non risolve: non può essere generalizzato per funzionare in categorie arbitrarie. ([Alcune categorie hanno una generalizzazione di '$', ma la maggior parte no - incluso 'Kleisli'] (http://stackoverflow.com/questions/31118949/generalising-like-control-category-generalises/31120454#31120454) .) Oltre a ciò, lo stile point-free è spesso più conciso, può essere in qualche modo più semplice refactored e non richiede di introdurre un nome di variabile ... tuttavia, questi non sono sempre vantaggi; a volte point-free è più difficile da capire ("codice inutile"). – leftaroundabout

+1

Quindi, sono '<=<' and '> =>' anche casi speciali di '<<<' and '> >>' che funzionano per le monadi? –