wake-up-neo.com

Wann sollte man ein Kleisli benutzen?

Ich bin kürzlich über das Konzept eines Kleisli gestolpert und jedes Tutorial/Link/jede Referenz, die ich lese, motiviert die Verwendung von Kleisli über die folgenden Konstrukte:

  1. Komponieren von Funktionen, die Monaden zurückgeben: f: a -> m[b] Mit g: b -> m[c] - Ich denke, die Definition einer Monade erfasst diesen Fall bereits - do/bind/for/flatMap Mach das. Man muss sich nicht auf das Kleisli-Konstrukt stützen, um dies zu erreichen. Dies kann also nicht der "primäre" Anwendungsfall einer Kleisli IMO sein.
  2. Konfiguration einfügen: Diese besagt, dass, wenn mehrere Objekte (Typen, Fall-/Datenklassen usw.) ein Config injiziert haben müssen, dann a Das Kleisli-Konstrukt kann verwendet werden, um die wiederholbare Injektion zu abstrahieren. Es gibt zahlreiche Möglichkeiten, dies zu erreichen (z. B. mit implicits in Scala), sodass das Aufrufen eines Kleisli möglicherweise nicht erforderlich ist. Auch hier ist IMO kein "primärer" Anwendungsfall.
  3. Monadentransformatoren : Ich habe kein solides Verständnis dafür, aber hier ist meine Interpretation: Wenn Sie die Notwendigkeit haben, "Monaden zu komponieren", brauchen ein Konstrukt, das es erlaubt Sie parametrisieren die Monaden selbst. Zum Beispiel könnte M1[M2[M1[M2[a]]]] In [M1[M2[a]]] Transformiert werden, wobei könnte (ich kann mich irren) über monadische Grenzen abgeflacht sein to mit einem a -> M3[b] (sagen wir) zusammensetzbar sein. Für dieses könnte uns ein Kleisli-Tripel und rufen Sie das Konstrukt auf, denn wenn Sie es von Grund auf neu machen würden, könnten Sie einfach neu erfinden das Kleisli. Dies scheint ein guter Kandidat zu sein, um die Verwendung eines Kleisli zu rechtfertigen. Ist das richtig?

Ich glaube, #1-#2 Oben sind "sekundäre Verwendungen". Das heißt, wenn Sie zufällig das Kleisli-Konstrukt verwenden, können Sie auch Muster zum Erstellen von Funktionen abrufen, die Monaden sowie Konfigurationsinjektion zurückgeben. Sie können jedoch nicht motivierende Probleme die Macht von Kleislis befürworten.

Unter der Annahme, dass zur Lösung des vorliegenden Problems die am wenigsten leistungsfähige Abstraktion verwendet wird, welche motivierenden Probleme können verwendet werden, um ihre Verwendung zu demonstrieren?

Alternative These : Es ist durchaus möglich, dass ich völlig falsch liege und mein Verständnis von Kleislis falsch ist. Mir fehlt der notwendige kategorietheoretische Hintergrund, aber es ist könnte sein, dass ein Kleisli ein orthogonales Konstrukt ist das anstelle von Monaden verwendet werden kann und sie (Kleisli) sind eine kategorietheoretische Linse, durch die wir die Probleme der Funktionswelt betrachten (dh ein Klesli umhüllt einfach eine monadische Funktion a -> M[b] und jetzt können wir auf einer höheren Abstraktionsebene arbeiten, auf der die Funktion das Objekt von = ist Manipulation gegen ein Objekt von Verwendung). Daher kann die Verwendung von Kleisli einfach als " Funktionale Programmierung mit Kleisli" verstanden werden. Wenn dies wahr ist, dann gibt es sollte eine Situation, in der ein Kleisli ein Problem lösen kann besser als bestehende Konstrukte und wir kehren zum Thema a zurück Motivationsproblem. Es ist ebenso wahrscheinlich, dass es an sich kein so motivierendes Problem gibt, wenn es einfach eine Linse ist, die verschiedene Lösungen für dasselbe Problem bietet. Welches ist es?

Es wäre sehr hilfreich, etwas Input zu bekommen, um den Bedarf an Kleislis zu rekonstruieren.

27
PhD

Manchmal möchten wir Berechnungen möglicherweise so strukturieren, dass sie weniger aussagekräftig, "starrer" als die vollständige Monad -Schnittstelle, aber möglicherweise auch besser überprüfbar sind. Kleislis kann verwendet werden, um monadische Effekte in diese Berechnungen einzubetten.

Stellen Sie sich zum Beispiel vor, wir erstellen Berechnungs-Pipelines, an die jedem Schritt eine Art Anmerkung zugeordnet ist. Eine Anmerkung könnte eine Schätzung der Zeit zum Abschließen des Schritts oder einer anderen mit dem Schritt verbundenen Ressource darstellen. Wir möchten in der Lage sein, die akkumulierten Anmerkungen für eine gesamte Pipeline zu überprüfen, bevor ihre Auswirkungen tatsächlich "ausgeführt" werden:

import Prelude hiding (id,(.))
import Control.Category (Category,(.),id)
import Control.Arrow (Kleisli (..))

data Step w m i o = Step w (Kleisli m i o) 

instance (Monoid w, Monad m) => Category (Step w m) where
    id = Step mempty (Kleisli pure)
    (.) (Step wf f) (Step wg g) = Step (wg <> wf) (f . g)

Damit es funktioniert:

main :: IO ()
main = do
    let Step w (Kleisli _) = 
              Step "b" (Kleisli putStrLn) 
            . Step "a" (Kleisli (\() -> getLine))
    putStrLn w
    -- result: ab
0
danidiaz