Ich arbeite über das Online-Buch LYAH (der Link führt Sie direkt zu der Abschnitt, der meine Frage betrifft).
Der Autor definiert einen Binärbaumdatentyp und zeigt an, wie eine Instanz des Typs Faltbar (definiert in Data.Foldable) durch Implementierung der Funktion faltMap erstellt werden kann:
%Vor%Die Typdeklaration von foldMap lautet wie folgt:
%Vor%Es braucht also eine Funktion, die eine Instanz vom Typ "a" akzeptiert und ein Monoid zurückgibt.
Als Beispiel erstellt der Autor eine Tree-Instanz
%Vor%und führt die folgende Faltung durch (definiert für faltbare Typen):
%Vor%Meine Frage ist, wie Haskell herausfindet, dass die Addition über den Integer-Typ - Haskells Abfrage nach dem Typ von testTree gibt Tree [Integer] - als Monoid-Operation betrachtet werden kann (wenn meine Terminologie korrekt ist)?
(Mein eigener Versuch der Antwort: Der Autor einige Absätze vor diesem Abschnitt beschreibt, wie der Typ Num auf zwei verschiedene Arten als Monoid -Typ interpretiert werden kann; Indem Sie sie in Summe und Produkt einschließen, geben Sie mit (+) und (*) die Funktionen mappend und 0 und 1 als mempty -Element ist der Typ von "a" in ( Baum a), der irgendwie zum Sum -Typ gehört (wie Haskell unterschiedlich) Interpretiert numerische Werte entsprechend dem Kontext oder ist es etwas ganz anderes?]
Meine Frage ist, wie Haskell herausfindet, dass die Addition über den Integer-Typ - Haskell für den Typ von testTree anzeigend Tree [Integer] - als eine monoale Operation betrachtet werden kann (wenn meine Terminologie korrekt ist)?
Es kann nicht! Tatsächlich gibt es keine Monoid
-Instanz für Integer
.
Verstehen Sie mich jetzt nicht falsch - ganze Zahlen sind ein Monoid unter Zusatz. Sie sind jedoch auch ein Monoid unter Multiplikation, und Haskell hat keine Möglichkeit zu wissen, was zu verwenden ist, daher die newtype
-Wrapper.
Aber ... nichts davon ist hier passiert. Weiter ...
(Mein eigener Versuch der Antwort: Der Autor ein paar Absätze vor diesem Abschnitt beschreibt, wie der Num-Typ auf zwei verschiedene Arten als Monoid-Typ interpretiert werden kann, indem man sie mit (+) und (*) als Mappend - Funktionen und 0 und 1 als Mempty - Element. Wird der Typ von "a" in (Baum a) irgendwie als zum Sum - Typ gehörig hergeleitet (die Art, wie Haskell verschiedene Zahlenwerte nach dem Kontext) oder ist es etwas ganz anderes?]
Keine schlechte Schätzung, aber diese Art von Inferenz (das Finden der Instanz mit Sum
basierend auf den Argumenten, die Sie gegeben haben) ist jenseits dessen, was Haskell für Sie tun kann.
Hier gibt es zwei wichtige Punkte: Erstens wird die Einschränkung Monoid
nur für bestimmte Funktionen verwendet, nicht für allgemeine Falten. Insbesondere benötigt foldl
nicht unbedingt eine Monoid
-Instanz, da Sie sowohl die binäre Operation als auch den Anfangswert für die Verwendung angeben.
Der zweite Punkt ist, was ich vermute, dass Sie wirklich danach sind - wie erstellt er ein generisches foldl
, das kein Monoid
benötigt, wenn alles, was Sie definiert haben, foldMap
ist, was macht das? Um das zu beantworten, können wir einfach schauen bei der Standardimplementierung von foldl
:
Hier ist Endo
ein anderes newtype
wrapper , speziell für die Funktionen a -> a
, die die Monoid
der Komposition angeben, mit id
als Identität, während Dual
ist ein Wrapper , der die Richtung von Monoid
umkehrt. Das Monoid
, das es hier verwendet, ist also so, dass es Verwendungen von (+)
zusammen mit der Funktionszusammensetzung kleben kann, und dann das Ergebnis auf den Startwert anwenden.
Das Monoid wird hier nicht verwendet. Die letzte Zeile verwendet F.foldl
mit der Signatur F.Foldable t => (a -> b -> a) -> a -> t b -> a
. Grundsätzlich verwenden Sie ein Monoid manuell, indem Sie (+) und 0 eingeben.
Wenn Sie ein Monoid 'implizit' verwenden möchten, können Sie F.fold
(mit der Signatur (F.Foldable t, Monoid m) -> t m -> m
) verwenden. In diesem Fall erhalten Sie Folgendes, wenn Sie es versuchen:
Nun beschwert sich GHCI, dass es für Integer keine Monoid-Instanz gibt, wie es sollte. Sie müssen entweder Summe oder Produkt auswählen, indem Sie die Ganzzahl umbrechen. Dazu können wir F.foldMap
(Signatur (F.Foldable t, Monoid m) => (a -> m) -> t a -> m
) verwenden:
Tags und Links haskell type-inference