2014-09-08 15 views
6

ich einen Code haben, die Art, wie diese aussieht, den gesamten Code zu ignorieren, die nicht relevant für meine Frage ist:eine Funktion Haskell Refactoring, die den Reader Monade verwendet

import qualified Control.Monad.Reader as Reader 

data FooEnv = FooEnv { bar :: Int -> Int } 
type FooReader = Reader.Reader FooEnv 

foo :: Int -> FooReader String 
foo i = Reader.liftM show $ bar' i 
    where 
    bar' i' = do 
     bar'' <- Reader.asks bar 
     return $ bar'' i' 

Gibt es eine Weg, dies zu überdenken? Insbesondere stört mich die verschachtelte bar' Funktion am meisten. Kann dies zu einer Linie verdichtet werden?

Antwort

9

Wir können ein wenig rationale Argumentation machen. Zuerst schauen wir uns bar' an. Ich werde es in dieser Form schreiben

asks bar >>= \z -> return (z i) 

Es stellt sich heraus, dass liftM definiert ist liftM f m = m >>= \a -> return (f a) zu sein, die das Muster oben passt. Lassen Sie uns so ersetzen Sie es mit

liftM ($ i) (asks bar) 

Dann haben wir foo als

liftM show (liftM ($ i) (asks bar)) 

Oder ein bisschen geschrieben besonders

liftM show . liftM ($ i) $ asks bar 

Wenn wir wissen, dass liftM ist fmap wir das erkennen können Functor Gesetz zu spielen hier

fmap show . fmap ($ i) $ asks bar -- equals 
fmap (show . ($ i)) $ asks bar 

Ich bin nicht persönlich ein großer Fan von ($ i) als Funktion verwenden, so wollen wir es als eine explizite Lambda

fmap (\f -> show (f i)) (asks bar) 

Jetzt neu schreiben, könnten wir entscheiden, die asks zu beseitigen, indem bar an der Aufrufstelle mit (dh verwenden bar als Funktion des Typs bar :: FooEnv -> Int -> Int

fmap (\f -> show (bar f i)) ask 

und als letzter Trick, könnten wir flip gehen sinnlos in der fmap ped Funktion und sogar die Verwendung von asks (dank Ørjan Johansen) return

fmap (show . flip bar i) ask -- or even 
show . flip bar i <$> ask  -- or even 
asks (show . flip bar i) 

Ich sage nicht, dass dies der lesbarste oder wunderbarste Weg ist, um diese Aufgabe zu erfüllen, aber Sie können sehen, wie wir die Stücke mit Hilfe von Gleichargumentation zerlegen können.

+2

Beachten Sie, dass 'asks f' gleichbedeutend ist mit' f <$> ask', also abhängig von Ihrem Geschmack können Sie es am Ende wieder einführen: 'fragt $ show. Flip-Bar i' –

+0

Danke, @ j-Abrahamson! Die detaillierten Schritte sind sehr hilfreich. Ich hätte aber genauer sein sollen, dass ich "bar" nicht in "foo" einreihen möchte. Ich werde jedoch daran arbeiten, die Schritte, die Sie unternommen haben, zu verstehen, damit ich versuchen kann, eine punktfreie Version von 'bar' zu erstellen. Ich bevorzuge 'ask' zu' ask', also danke auch dir, @ Ørjan-johansen, dass du diesen letzten Schritt hinzugefügt hast. – arussell84

+0

Ich habe es herausgefunden: 'bar 'i' = fragt $ flip bar i'' oder' bar '= fragt. Flipbar " – arussell84

Verwandte Themen