2017-09-24 5 views
2

Anwendung Ich bin mir bewusst, dass ich die Funktion Monade verwenden kann, um ein Konstrukt wie die unten zu erreichen (wo ich das Argument in mehr Anrufen wiederverwenden, ohne es explizit Referenzierung):Ausführen eine Transformation mit dem Eingang, bevor die Funktion Monade

compute_v0 :: String -> String 
compute_v0 = do 
    x <- length -- (using the argument implicitly here) 
    top <- head -- (and here) 
    return (replicate x top) 

Das Ergebnis der obigen Funktion für: compute "1234""1111"

Meine Frage wäre: Wie würde ich eine Transformation auf die ‚versteckten‘ Argument anwenden, bevor das tun Block ausgeführt wird (man stelle würde ich mag „abcd anhängen "zur Liste).

Meine erste Lösung:

compute_v1 :: String -> String 
compute_v1 = compute_v1' . (++ "abcd") 

compute_v1' ::String -> String 
compute_v1' = do 
    x <- length 
    top <- head 
    return (replicate x top) 

Das Ergebnis für compute "1234" wäre jetzt "11111111". Dies erledigt zwar den Job, aber ich würde lieber versuchen, es in einem einzigen Code-Block definiert zu halten.

Der nächstgelegene ich tatsächlich bekommen konnte umfassen die Transformation, während immer noch den Stil von Code (v0) zu halten war diese:

compute_v2 :: String -> String 
compute_v2 = (++ "abcd") >>= \r -> do 
    let x = length r 
    let top = head r 
    return $ replicate x top 

Aber ich hatte noch eine Lambda enthalten, eine Menge let Bindungen verwenden und verweisen Sie explizit auf das Lambda-Argument. Gibt es bessere Möglichkeiten, ein solches Konstrukt zu erreichen?

+0

'compute_v1 = LiftA2 replizierten Länge Kopf. (++ "abcd") ' – 4castle

+0

' compute_v1 = (replizieren <$> Länge <*> Kopf). (++ "abcd") ' – Redu

Antwort

5

Da alle Monad Instanzen auch Functor Instanzen haben und die Funktion Instanz Functor hat fmap = (.), können Sie

compute :: String -> String 
compute = flip fmap (++ "abcd") $ do 
    x <- length 
    top <- head 
    return $ replicate x top 

Einige Pakete haben (wie microlens und lens) definieren (<&>) = flip fmap, so dass Sie

schreiben
compute :: String -> String 
compute = (++ "abcd") <&> do 
    x <- length 
    top <- head 
    return $ replicate x top 

Es gibt auch eine Category Instanz für (->), die giv es uns (>>>) = flip (.). Das mag etwas klarer, optisch:

compute :: String -> String 
compute = (++ "abcd") >>> do 
    x <- length 
    top <- head 
    return $ replicate x top 
+0

Ich würde' fmap' nicht benutzen, wenn es '(.)' verkleidet ist. Ich würde 'flip (.) (++" abcd ")' oder '(. (++" abcd "))' 'verwenden.(Nun, um ehrlich zu sein, würde ich das niemals im monadischen Stil schreiben, aber das OP scheint damit experimentieren zu wollen) – chi

+0

@chi Das ist ein guter Punkt, aber ich wollte den Gedankenprozess etwas hervorheben, der mich dazu führte (was war: Da wir seine monadischen Eigenschaften verwenden, versuchen Sie zu sehen, was die "Functor" -Instanz tut). –

+0

Ich verstehe. Ja, ich würde diesem Prozess zustimmen. – chi

4

Sie so etwas tun könnte:

compute_v2 :: String -> String 
compute_v2 = do 
    x <- length 
    top <- head 
    return $ replicate x top 
    <$> (++ "abcd") 

AFAIK ist die Monade in Frage der Reader Monade genannt, und es ist auch ein Functor.

*Q46393211> compute_v2 "1234" 
"11111111" 
*Q46393211> compute_v2 "71" 
"777777" 
+1

@chi Kein Parse Fehler mit dem Code in einem Modul in GHCi geladen. Ich habe nicht versucht, es "wirklich" zu kompilieren ... –

+0

Ich mag diese "einfachen" Haskell-Fragen und Antworten, die meinen Kopf in kürzester Zeit drehen lassen. Mein aktuelles Verständnis davon: '<$>' ist der Infix-Operator von 'fmap' (nachgeschlagen [hier] (https://stackoverflow.com/questions/37286376/what-does-mean-in-haskell)). Alles auf der linken Seite wäre eine Funktion "a-> b", die rechte die "f a". Also ist das eine Funktion, die man als Funktor betrachtet? Für den 'do'-Block selbst ist das die 'List'-Monade, weil Strings Charts-Listen sind? –

+0

@StefanHanke Nein, es ist die Funktion Monade (und Funktion Funktor) den ganzen Weg. Der Typ der Ausdrücke rechts von den '<-'s sind Funktionstypen, was eine Möglichkeit ist, zu erkennen, dass es sich um die Funktion monad-Instanz handelt, die verwendet wird. Das Parsen ist hier (meiner Meinung nach) etwas komisch, aber es scheint zu analysieren als 'compute_vs = (do {... block code here ...}) <$> (++ "abcd") '. Ich würde die Parens persönlich explizit angeben, wenn ich so etwas hätte. –

1

MonadReader class hat die Methode local hierfür und (->) r ist eine Instanz, so

import Control.Monad.Reader (local) 

compute_v3 ::String -> String 
compute_v3 = local (++ "abcd") $ do 
    x <- length 
    top <- head 
    return (replicate x top) 

sollte funktionieren (kann im Augenblick nicht-Test).

Verwandte Themen