Arrows Ein Vortrag von Mario Rauschenberg, Bjarne Großmann Agenda Einleitung Funktionen, Monaden und Arrows Funktionen, Monaden und Arrows Arrows im Detail Beispiel 15.01.2009 Bjarne Großmann, Mario Rauschenberg 2 Einleitung Was sind eigentlich „Arrows“? Lediglich eine Verallgemeinerung der Monaden! ??? 15.01.2009 Bjarne Großmann, Mario Rauschenberg 3 Einleitung Quizfrage: Was ist eine Monade? a) Abstrakter Datentyp b) Beschreibung einer einheitlichen Schnittstelle c) Containerklasse für unterschiedliche Typen d) Verpackte Berechnungen mit Seiteneffekten ) g , g e) Strategie, um Berechnungen zu kombinieren f) Ich hab keine Ahnung 15.01.2009 Bjarne Großmann, Mario Rauschenberg 4 Back to the Roots Back to Funktionen und ihre Komposition f g h fgh fgh :: a ‐> b >b :: b ‐> c :: c ‐> d :: a > d :: a ‐> d = h . g . f a b f 15.01.2009 b c g c d h Bjarne Großmann, Mario Rauschenberg 5 Back to the Roots Back to Komplexere Funktionen f1,g1,h1 f1 1 h1 f2,g2,h2 f3,g3,h3 f4 g4 h4 f4,g4,h4 :: a ‐> Maybe >M b b :: a ‐> (b, s) :: a ‐> [b] :: a > (s > (a s)) :: a ‐> (s ‐> (a, s)) fgh = fn . gn . hn ??? a Maybe b f 15.01.2009 b Maybe c g Bjarne Großmann, Mario Rauschenberg 6 Beispiel: Maybe Beispiel: Maybe f g h fgh :: a :: a ‐>> Maybe b Maybe b :: b ‐> Maybe c :: c ‐> Maybe d :: a ‐>> Maybe d :: a Maybe d a b fgh 1. Lösungsversuch fgh g x = case f x of Nothing ‐> Nothing Just y ‐> case g y of Nothing ‐> Nothing Just z ‐> h z 15.01.2009 Bjarne Großmann, Mario Rauschenberg 7 Beispiel: Maybe Beispiel: Maybe f g h f h fgh :: a ‐> Maybe b :: b ‐> Maybe c :: c ‐> Maybe d :: a ‐> Maybe d b d (a > Maybe b) (Maybe (a ‐> Maybe b) (Maybe a ‐> Maybe a > Maybe b) helper f f* 2. Lösungsversuch helper helper f Nothing helper f (Just x) :: (a :: (a ‐>> Maybe b) Maybe b) ‐>> (Maybe a (Maybe a ‐>> Maybe b) Maybe b) = Nothing = f x fgh = (helper h) . (helper g) . f 15.01.2009 Bjarne Großmann, Mario Rauschenberg 8 Beispiel: Tupel Beispiel: Tupel f g h fgh :: a ‐> (b, String) :: b ‐> (c, String) :: c ‐> (d, String) :: a ‐> (d, String) helper :: (a ‐> (b, String)) ‐> ((a, String) ‐> (b, String)) helper g (fx, fs) = let (gx, gs) = g fx in (gx, fs++gs) fgh = (helper h) . (helper g) . f ( ) ( ) 15.01.2009 Bjarne Großmann, Mario Rauschenberg 9 Beispiel: Liste Beispiel: Liste f g h fgh :: a ‐> [b] :: b ‐> [c] :: c ‐> [d] :: a ‐> [d] helper helper f x :: (a ‐> [b]) ‐> ([a] ‐> [b]) = concat (map f x) fgh = (helper h) . (helper g) . f 15.01.2009 Bjarne Großmann, Mario Rauschenberg 10 Beispiel: Status Beispiel: Status f g h fgh :: a ‐> (s ‐> (b, s)) :: b ‐> (s ‐> (c, s)) :: c ‐> (s ‐> (d, s)) :: a ‐> (s ‐> (d, s)) helper helper g x s :: (a ‐> (s ‐> (b, s))) ‐> ((s ‐> (a, s)) ‐> (s ‐> (b, s))) = let (x1, s1) = x s in g x1 s1 fgh = (helper h) . (helper g) . f ( ) ( ) 15.01.2009 Bjarne Großmann, Mario Rauschenberg 11 Beispiel: Zusammenfassung Beispiel: Zusammenfassung f1 helper1 f2 helper2 f3 helper3 f4 helper :: a ‐> Maybe b :: (a ‐> Maybe b) ‐> (Maybe a ‐> Maybe b) :: a ‐> (b, s) :: (a ‐> (b, s)) ‐> ((a, s) ‐> (b, s)) :: a ‐> [b] :: (a ‐> [b]) ‐> ([a] ‐> [b]) :: a ‐> (s ‐> (d, s)) :: (a ‐> (s ‐> (b, s))) ‐> ((s ‐> (a, s)) ‐> (s ‐> (b, s))) fgh = (helper hn) . (helper gn) . fn ( ) ( ) 15.01.2009 Bjarne Großmann, Mario Rauschenberg 12 Monaden newtype MyMonad t = M Maybe t newtype MyMonad t = M (t, String) newtype MyMonad t = M [t] newtype MyMonad t = M (s ‐> (t, s)) 15.01.2009 f helper :: a ‐> M b :: (a ‐> M b) ‐> (M a ‐> M b) :: (a ‐> M b) ‐> M a ‐> M b (a > M b) > M a > M b :: M a ‐> (a ‐> Mb) ‐> M b (>>=) = helper = helper fgh x return = f x >>= g >>= h ?=? x >>= f >>= g >>= h ?=? x >>= f >>= g >>= h :: a ‐> M a fgh x = return x return x >>= f f >>= g g >>= h h Bjarne Großmann, Mario Rauschenberg 13 Monaden In Haskell: class Monad m where return :: a ‐> m a (>>=) :: m a ‐> (a ‐> m b) ‐> m b Maybe a a ‐> b [a] s ‐> (a, s) Either e Monade 15.01.2009 Bjarne Großmann, Mario Rauschenberg 14 Funktionskomposition Funktionen kombinieren f :: a ‐> b g :: b ‐> c Bisher fgfg :: a ‐> c = f . g Funktionen als Parameter :: (a ‐> b) ‐> (b ‐> c) ‐> (a ‐> c) comb comb h k = k . h (.) für einfache Funktionen 15.01.2009 Bjarne Großmann, Mario Rauschenberg 15 Funktionskomposition Funktionen kombinieren f :: a ‐> m b g :: b ‐> m c Bisher fg :: a ‐> m c fg x = (f x) >>= g Funktionen als Parameter comb comb h k x :: (a ‐> m b) ‐> (b ‐> m c) ‐> (a ‐> m c) = (h x) >>= k (>>=) für monadische Funktionen? ((>>=) :: m a ‐> (a ‐> m b) ‐> m b ) ( ) 15.01.2009 Bjarne Großmann, Mario Rauschenberg 16 Funktionskomposition Abstraktion des Operators comb newtype Kleisli m a b mab (>‐>) K f (>‐>) K g :: (a ‐> m b) ‐> (b ‐> m c) ‐> (a ‐> m c) = K { runK K { runK :: a ‐> m b } a >mb} :: Kleisli m a b ‐> Kleisli m b c ‐> Kleisli m a c = K (\x ‐> f x >>= g) Der erste Arrow: Kleisli Arrow! g Anwendung ähnlich wie bei Monaden f :: K m a b g :: K m b c fg x = runK (f >‐> g) x 15.01.2009 Bjarne Großmann, Mario Rauschenberg 17 Arrows Weitere Abstraktion Kleisli Arrow nicht nur für Monaden: f newtype Arrow b c (>>>) (>>>) arr :: b ‐> c = A ( runA :: b ‐> c) :: A b c ‐>> A c d :: A b c A c d ‐>> A b d Abd :: (b ‐> c) ‐> A b c Arrows für beliebige Funktionen f :: A a b g :: A b c fg x x = runA runA (f (f >>> g) x >>> g) x 15.01.2009 Bjarne Großmann, Mario Rauschenberg 18 Was sind Arrows? Was sind Arrows? Erklärung von Wikibooks Kombination von Funktions Kombination von Funktions‐Objekten Objekten (Roboter) mit verschiedenen In‐ und Outputs (Fließbänder) 15.01.2009 Bjarne Großmann, Mario Rauschenberg 19 arr Verknüpfung mit In‐ und Output arr :: Arrow a => (b ‐> c) ‐> a b c 15.01.2009 Bjarne Großmann, Mario Rauschenberg 20 (>>>) Output von f als Input von g (>>>) :: Arrow a => a b c ‐> a c d ‐> a b d 15.01.2009 Bjarne Großmann, Mario Rauschenberg 21 returnA Arrow – Identität returnA :: Arrow a => a b b Arrow a > a b b returnA = arr id 15.01.2009 Bjarne Großmann, Mario Rauschenberg 22 Unterschied zu Monaden Unterschied zu Monaden Arrows sind eine Erweiterung von Monaden Monaden sind eine Erweiterung von sind eine Erweiterung von Funktionen Also: Arrows Al A abstrahieren Funktionen b hi F ki Arrows haben expliziten Input p p Funktion Monade Arrow f m a 15.01.2009 Bjarne Großmann, Mario Rauschenberg 23 Monaden durch Arrows Monaden durch Arrows newtype yp Kleisli m a b = K (a ‐> m b) ( ) instance Monad m => Arrow (Kleisli m) where arr f = K (\b ‐> return f b) K f >>> K g = K (\b ‐> f b >>= g) 15.01.2009 Bjarne Großmann, Mario Rauschenberg 24 „The real flexibility with arrows comes with the „The real flexibility with arrows comes with the ones that aren't monads, otherwise it's just a clunkier syntax syntax” ‐ Philippa Cowderoy 15.01.2009 Bjarne Großmann, Mario Rauschenberg 25 first & second & second Mehrere Inputs von denen einer verarbeitet wird. first :: Arrow a => a b c ‐> a (b, d) (c, d) second :: Arrow a => a b c ‐> a (d, b) (d, c) Arrow a > a b c > a (d b) (d c) 15.01.2009 Bjarne Großmann, Mario Rauschenberg 26 ( ) (***) Zwei Inputs durch jeweils anderes j Funktionsobjekt bearbeitet (***) Arrow a > a b c > a d e > a (b d) (c e) (***) :: Arrow a => a b c ‐> a d e ‐> a (b,d) (c,e) 15.01.2009 Bjarne Großmann, Mario Rauschenberg 27 (&&&) Ein Input wird in beide Funktionen „geklont“. (&&&) Arrow a > a b c > a b d > a b (c d) (&&&) :: Arrow a => a b c ‐> a b d ‐> a b (c,d) 15.01.2009 Bjarne Großmann, Mario Rauschenberg 28 Wozu das ganze? Wozu das ganze? Generalisierung von Monaden bzw. g Funktionen und „Funktionsartigen“ Größere Flexibilität als bei Monaden „Stream‐Prinzip“ S Pi i “ 15.01.2009 Bjarne Großmann, Mario Rauschenberg 29 Funktionen als Arrows Funktionen als Arrows instance Arrow (‐>) where arr f = f f f first f = f *** id second f = id *** f ((***)) f g f g ~(x (x,y) = (f x, g y) y) = (f x g y) 15.01.2009 Bjarne Großmann, Mario Rauschenberg 30 Parser Beispiel Parser‐Beispiel Monadischer HTML‐Parser Input: <xhtml> Input: <xhtml> <html> <body> <?php> Ineffizient! 15.01.2009 fail! Bjarne Großmann, Mario Rauschenberg 31 Parser Beispiel Parser‐Beispiel Erweiterung von Swierstra und Duponcheel: Vorausschauendes Parsen Input: <xhtml> <html> <body> <? h > <?php> fail! 15.01.2009 Bjarne Großmann, Mario Rauschenberg 32 Parser Beispiel Parser‐Beispiel Monadischer Parser newtype yp Parser s a = P ([s] ‐> Maybe ([ ] y ((a,[s])) ,[ ])) symbol :: s ‐> Parsers s s symbol s = P (\xs ‐> case xs of [ ] ‐> nothing (x : xs‘) ‐> if x == s then just (s, xs‘) else nothing ) 15.01.2009 Bjarne Großmann, Mario Rauschenberg 33 Parser Beispiel Parser‐Beispiel Monadische Parser kombinieren instance MonadPlus Parsers where P a (+++) P b = P (\s ‐> case a s of Just (x, s‘) ‐> Just (x, s‘) Nothing ‐> b s ) Problem: „Space Leak Problem: Space Leak“ 15.01.2009 Bjarne Großmann, Mario Rauschenberg 34 Parser Beispiel Parser‐Beispiel Erweiterung data Parser s a b = P (StaticParser ( s) (DynamicParser )( y s a b)) data StaticParser s = SP Bool [s] newtype DynamicParser s a b = DP ( (a, [s]) ‐> (b, [s]) ) spChar :: Char ‐> StaticParser Char spChar c = SP False [c] dpChar :: Char ‐> DynamicParser Char Char Char d Ch dpChar c = DP (\ (\ ( _ , x:xs) ‐> (c, xs) ) ( ) ( )) simple :: Char ‐> Parser Char Char Char simple c = P (spChar i l P ( Ch c ) (dpChar ) (d Ch c)) 15.01.2009 Bjarne Großmann, Mario Rauschenberg 35 Parser Beispiel Parser‐Beispiel Instance MonadPlus Parsers where P (SP empty1 start1) DP (dp1) (+++) P (SP empty2 start2) DP (dp2) = P ( SP (empty1 || empty2) (start1++start2) DP (\xss ‐> case xss of [ ] = if empty1 then dp1 [] else dp2 [] j@(x:xs) = if x `in` start1 then dp1 j else if x `in` start2 then dp2 j else if empty1 then dp1 j else dp2 j ) ) 15.01.2009 Bjarne Großmann, Mario Rauschenberg 36 Parser Beispiel Parser‐Beispiel Bind‐Operator (>>=) :: Parsers s a ‐> ( a ‐> Parsers s b) ‐> Parsers s b … ist nicht möglich, da der statische Teil von a „vergessen“ wird. “ id 15.01.2009 Bjarne Großmann, Mario Rauschenberg 37 Parser Beispiel Parser‐Beispiel Arrow‐Parser Instance Arrow (Parser s) where ( ) arr :: Arrow a => (b ‐> s) ‐> a b s arr f = P (SP True [ ]) (DP (\ (b,s) ‐> (f b, s) ) ) P (SP empty1 start1) DP (dp1) >>> P (SP empty2 start2) DP (dp2) = P ( SP (empty1 && empty2) (start1 `union` if empty1 then start2 else [ ]) DP (dp1 . dp2) ) 15.01.2009 Bjarne Großmann, Mario Rauschenberg 38 Anwendungsbeispiele von Arrows Anwendungsbeispiele von Arrows Parser (z.B. auch HXT) Automaten Stream‐Computing 15.01.2009 Bjarne Großmann, Mario Rauschenberg 39 Fazit Mächtiges Konzept für funktionsartige g g Vorgänge Allgemeinerer Entwurf als Monaden Weg von Pure‐Functions W P F i Verständnis ist „nicht einfach“ „ 15.01.2009 Bjarne Großmann, Mario Rauschenberg 40 Quellen (einige) Quellen (einige) http://www.haskell.org/haskellwiki h // h k ll /h k ll iki http://www.wikibooks.org John Hughes: Generalising Monads to Arrows: http //www cs chalmers se/~rjmh/Papers/arrows pdf http://www.cs.chalmers.se/~rjmh/Papers/arrows.pdf John Hughes: Programming with Arrows: http://www.cs.chalmers.se/~rjmh/afp‐arrows.pdf Hudak Courtney Nilsson Peterson: Arrows Robots and Reactive Functional Programming Hudak, Courtney, Nilsson, Peterson: Arrows, Robots http://www.haskell.org/yale/papers/oxford02/.oxford02.pdf Albert Lai: HXT Arrow Lessons: http://www.vex.net/~trebla/haskell/hxt‐arrow/index.xhtml p // / / / / 15.01.2009 Bjarne Großmann, Mario Rauschenberg 41