Der Versuch, das Nicht-Komponierbare zu komponieren: Erhebe alles

Es wird empfohlen, den ersten Artikel zu lesen, sofern dies noch nicht geschehen ist. Dieser Artikel wird kürzer sein, sich weniger auf Details als auf Funktionen konzentrieren.

Laut Stephen Diel zusammen mit abhängigen Typen eine schnellere Zusammenstellung und eine niedrigere Eintrittsschwelle; Algebraische Effekte sind eine der wichtigsten Aufgaben, die in Zukunft für Haskell gelöst werden.

Die Zukunft ist nicht weit weg, also müssen Sie jetzt anfangen.

Effekte auf andere Effekte übertragen


class Liftable eff schema where lift :: eff ~> schema 

Was bedeutet "Erhebung" im Wesentlichen? lift ist das gleiche pure / return, mit der Ausnahme, dass wir nicht den Wert in den Effekt eintauchen, sondern den Effekt in eine Art Transformator (in unserem Fall in die Transformatorschaltung):

 pure :: a -> ta lift :: ua -> tua 

Auf diese Weise können wir alle Effekte in einem bestimmten Transformator verwenden. Es ist einfach, neue Effekte einzuführen, aber später müssen wir sie alle interpretieren.

So können wir die erhöhten Effekte sicher komponieren:

 let f = lift get :: Configured _ t => t _ let g = lift Nothing :: Optional t => t _ let h = lift (failure _) :: Failable _ t => t _ let x = f *> g *> h :: (Applicative t, Configured _ t, Optional t, Failable _ t) => t _ 

Und reichen Sie sie in einer für uns passenden Reihenfolge ein:

 let y = pure _ :: Reader _ :> State _ :> Either _ :> Maybe := Int let z = pure _ :: State _ :> Either _ :> Maybe _ :> Reader := _ let x = f *> g *> h :: (Applicative t, Configured _ t, Optional t, Failable _ t) => t _ let xy = x *> y :: Reader _ :> State _ :> Either _ :> Maybe := _ let xz = x *> z :: State _ :> Either _ :> Maybe _ :> Reader := _ 

Passen Sie einige Effekte an andere an


 class Adaptable subeff eff | subeff -> eff where adapt :: subeff ~> eff 

Anpassung bedeutet, dass einige Effekte durch stärkere Effekte ersetzt werden können. Beispielsweise können die Effekte von Reader und Writer in State verwendet werden , da State lesen und schreiben und somit den gespeicherten Wert ändern kann:

 lift put :: Accumulated _ t => t _ lift get :: Configured _ t => t _ (lift . adapt $ put) :: Stateful _ t => t _ (lift . adapt $ get) :: Stateful _ t => t _ 

Wie ist das möglich? Im vorherigen Artikel haben wir State in zwei Effekte unterteilt:

 State s = (->) s :. (,) s 

Im Fall von Reader heben wir einfach den Pfeilfunktor auf die Statusebene an, und im Fall von Writer den Tupelfunktor:

 Reader s = (->) s Writer s = (,) s 

Wir können Failable an Optional anpassen, verlieren jedoch die Fehlerinformationen:

 (lift $ Just _) :: Optional t => t _ (lift $ failure _) :: Failable _ t => t _ (lift . adapt $ failure _) :: Optional t => t _ 

Effekte in Transformern ausführen


Um einen Effekt in einem Transformator zu interpretieren, reicht eine Run- Methode aus:

 let xy = x *> y :: Reader _ :> State _ :> Either _ :> Maybe := _ let xy' = run xy _ :: State _ :> Either _ :> Maybe := _ let xy'' = run xy' _ :: Either _ :> Maybe := _ let xy''' = run xy'' :: Maybe (Either _) _ 

Fazit und Beispiele


Im Moment können Sie also ohne freie / freie Monaden (und manchmal sogar ohne Monaden) mithilfe von joint Ihre Ausdrücke gemäß den von ihnen erzeugten Effekten eingeben. Alles, was Sie brauchen, ist eine Komposition von Funktoren.

Es gibt auch eine Präsentation aus einem Bericht zu diesem Thema auf der örtlichen Kundgebung in Rostow am Don, die in einem Browser angezeigt werden kann.

Die besten Beispiele sind solche, die der Realität so nahe wie möglich kommen. Ich liebe Musik, also können Sie sehen, wie dieses Effektsystem in einem Programm verwendet wird, das Alben von Bandcamp herunterlädt .

Source: https://habr.com/ru/post/de485518/


All Articles