Vor kurzem versuche ich, Haskell in einigen meiner realen Fallproduktionssysteme zu verwenden. Das Haskell-System bietet mir wirklich große Hilfe. Zum Beispiel, als ich merkte, dass ich eine Funktion vom Typ brauche
f :: (Foldable t, Monad m) => ( a-> b -> m b) -> b -> t a -> m b
Es gibt tatsächlich Funktionen wie foldM
, foldlM
und foldrM
.
Was mich jedoch wirklich schockiert hat, ist die Definition dieser Funktionen, wie zum Beispiel:
foldlM :: (Foldable t, Monad m) => (b -> a -> m b) -> b -> t a -> m b
foldlM f z0 xs = foldr f' return xs z0
where f' x k z = f z x >>= k
Die Funktion f'
muss also vom Typ sein:
f' :: a -> b -> b
wie von verlangt foldr
, b
muss dann von Art sein *-> m *
, damit die gesamte Definition von foldlM
sinnvoll sein könnte.
Ein weiteres Beispiel enthält Definitionen von liftA2
und<*>
(<*>) :: f (a -> b) -> f a -> f b
(<*>) = liftA2 id
liftA2 :: (a -> b -> c) -> f a -> f b -> f c
liftA2 f x = (<*>) (fmap f x)
Ich habe einige meiner eigenen Lösungen ausprobiert, bevor ich in den Quellcode geschaut habe. Aber die Lücke ist so groß, dass ich nicht glaube, dass ich jemals eine Lösung finden könnte, egal wie viele Codezeilen ich in Zukunft schreiben werde.
Meine Frage ist also, welche Art von Wissen oder welcher spezifische Mathematikzweig notwendig ist, damit jemand auf einer so stark abstrahierten Ebene argumentieren kann.
Ich weiß, dass die Kategorietheorie möglicherweise hilfreich ist, und ich verfolge diesen großartigen Vortrag schon lange und arbeite immer noch daran.
quelle
Antworten:
Im Allgemeinen würde ich mir Logik usw. vorstellen. Sie können es aber auch lernen, indem Sie es tun. :) Mit der Zeit bemerken Sie einige Muster, lernen Sie einige Tricks.
So
foldr
mit einem zusätzlichen Argument. Einige sehen es als Faltung in Funktionen, so dass sie durch.
undid
(die manchmal wirklich<=<
und sindreturn
) kombiniert werden können ,Einige finden es einfacher, es in einfacheren, syntaktischen Begriffen zu verstehen, wie
Wenn
g
also das zweite Argument nicht streng ist,s
kann es als Zustand dienen, der von links weitergegeben wird, obwohl wir als ein Beispiel rechts falten.quelle
Der beste Weg, es zu verstehen, ist es, es zu tun. Unten finden Sie eine Implementierung von
foldlM
usingfoldl
anstelle vonfoldr
. Es ist eine gute Übung, probieren Sie es aus und kommen Sie später zu der Lösung, die ich vorschlagen würde. Das Beispiel erklärt alle Überlegungen, die ich angestellt habe, um dies zu erreichen. Diese können sich von Ihren unterscheiden und voreingenommen sein, da ich bereits über die Verwendung eines Funktionsakkumulators Bescheid wusste.Schritt 1 : Versuchen wir,
foldlM
in Bezug auf zu schreibenfoldl
Hier erkennen Sie, dass dies
f'
rein ist und Sie das Ergebnis extrahieren müssen, umf
Übereinstimmung einzugeben. Die einzige Möglichkeit, einen monadischen Wert zu "extrahieren", ist der>>=
Operator. Ein solcher Operator muss jedoch direkt nach seiner Verwendung umbrochen werden.Fazit: Jedes Mal, wenn Sie am Ende diese Monade vollständig auspacken möchten , geben Sie einfach auf. Ist nicht der richtige Weg
Schritt 2 : Lassen Sie uns versuchen,
foldlM
in Form von zu schreiben,foldl
aber zuerst[]
als faltbar zu verwenden, da es einfach ist, Muster zu finden (dh wir müssen es eigentlich nicht verwendenfold
).Ok, das war einfach. Vergleichen Sie die Definition mit der üblichen
foldl
Definition für ListenCool!! Sie sind ziemlich gleich. Der triviale Fall handelt von genau der gleichen Sache. Der rekursive Fall ist etwas anders, Sie möchten etwas mehr schreiben wie :
foldlM' f (f z0 x) xs
. Wird aber nicht wie in Schritt 1 kompiliert, so dass Sie vielleicht denken, OK, ich möchte mich nicht bewerbenf
, nur um eine solche Berechnung zu halten und sie zu komponieren>>=
. Ich würde gerne etwas mehr schreiben,foldlM' f (f z0 x >>=) xs
wenn es Sinn hätte ...Schritt 3 Stellen Sie fest, dass das, was Sie akkumulieren möchten, eine Funktionszusammensetzung und kein Ergebnis ist. ( hier bin ich wahrscheinlich voreingenommen von der Tatsache, dass ich es bereits wusste, weil Sie es gepostet haben ).
Durch die Art
initFunc
und Verwendung unseres Wissens aus Schritt 2 (der rekursiven Definition) können wir daraus schließeninitFunc = return
. Die Definitionf'
kann zu wissen , abgeschlossen werden , dassf'
verwenden soll ,f
und>>=
.Wie Sie sehen können, ist es nicht soooo schwierig, dies zu tun. Es braucht Übung, aber ich bin kein professioneller Haskell-Entwickler und ich könnte es selbst tun. Es ist eine Frage der Übung
quelle
Monad
Fälle effizient ist .Sie benötigen keine spezifischen Kenntnisse in Mathematik, um eine Funktion wie zu schreiben
foldM
. Ich verwende Haskell bereits seit 4 Jahren in der Produktion und habe auch Probleme, diese Definition von zu verstehenfoldM
. Aber das liegt hauptsächlich daran, dass es schlecht geschrieben ist. Bitte nehmen Sie es nicht als persönlichen Fehler, wenn Sie einen obskuren Code nicht verstehen können. Hier ist eine besser lesbare Version vonfoldlM
Diese Funktion ist immer noch nicht die einfachste. Meistens, weil es eine nicht typische Verwendung hat,
foldr
bei der der Zwischenspeicher eine Funktion ist. Sie können jedoch einige Möglichkeiten erkennen, die eine solche Definition lesbarer machen:where
(damit Sie die Form der Argumente kennen).Nachdem Sie eine solche Funktion gesehen haben, können Sie jetzt die Technik des Gleichungsdenkens ausführen , um die Definition Schritt für Schritt zu erweitern und zu sehen, wie sie funktioniert. Die Fähigkeit, solche Funktionen zu entwickeln, hängt von der Erfahrung ab. Ich habe keine starken mathematischen Fähigkeiten und diese Funktion ist keine typische Haskell-Funktion. Aber je mehr Übung du hast, desto besser wird es :)
quelle