Klassenbeschränkungen für Monaden und Monaden

8

Ich versuche eine neue Monade zu schreiben, die nur eine Num enthalten kann. Wenn es fehlschlägt, gibt es 0 zurück, ähnlich wie die Maybe-Monade bei Versagen nichts zurückgibt.

Hier ist was ich bisher habe:

%Vor%

Haskell beklagt sich, dass es ein

gibt %Vor%

Es schlägt vor, dass ich einen Zusatz (Num a) zum Kontext der Typ-Signatur für jede meiner Monadenfunktionen hinzufüge, aber ich habe es versucht, und dann beschwert es sich, dass sie "für immer" a arbeiten müssen.

Beispiel:

%Vor%

Weiß jemand, wie man das repariert?

    
Ian 11.03.2014, 00:06
quelle

3 Antworten

14

Die vorhandene Monad typeclass erwartet, dass Ihr Typ für alle möglichen Argumenttypen funktioniert. Betrachte Maybe : in Maybe a , a ist überhaupt nicht eingeschränkt. Grundsätzlich können Sie keine Monade mit Einschränkungen haben.

Dies ist eine grundlegende Einschränkung der Definition der Monad -Klasse - ich kenne keinen Weg, um es zu umgehen, ohne das zu ändern.

Dies ist auch ein Problem bei der Definition von Monad Instanzen für andere gebräuchliche Typen wie Set .

In der Praxis ist diese Einschränkung tatsächlich ziemlich wichtig. Beachten Sie, dass (normalerweise) Funktionen nicht Instanzen von Num sind. Dies bedeutet, dass wir Ihre Monade nicht verwenden können, um eine Funktion zu enthalten! Dies begrenzt wirklich wichtige Operationen wie ap ( <*> von Applicative ), da dies von einer Monade abhängt, die eine Funktion enthält:

%Vor%

Ihre Monade würde nicht viele übliche Anwendungen und Idiome unterstützen, die wir von normalen Monaden erwarten. Dies würde seinen Nutzen eher einschränken.

Als Nebenbemerkung sollten Sie generell fail vermeiden. Es passt nicht wirklich in die Klasse Monad : Es ist eher ein historischer Zufall. Die meisten Leute stimmen zu, dass Sie es im Allgemeinen vermeiden sollten: Es war nur ein Hack, um mit fehlgeschlagenen Musterübereinstimmungen in Do-Notation umzugehen.

Das heißt, wenn man sich ansieht, wie man eine eingeschränkte Monad-Klasse definiert, ist das eine großartige Übung, um ein paar Haskell-Erweiterungen zu verstehen und etwas fortgeschrittenes Haskell zu lernen.

Alternativen

Im Hinblick auf die Nachteile gibt es hier einige Alternativen: Ersetzungen für die Standardklasse Monad , die eingeschränkte Monaden unterstützen

.

Einschränkungsarten

Ich kann mir ein paar mögliche Alternativen vorstellen. Der modernste würde die Erweiterung ConstraintKind in GHC nutzen, mit der Sie Typklassenbeschränkungen als Arten vereinheitlichen können. In diesem Blogpost wird beschrieben, wie eine eingeschränkte Monade mithilfe von Einschränkungsarten implementiert wird. Sobald ich es gelesen habe, werde ich es hier zusammenfassen.

Die Grundidee ist einfach: Mit ConstraintKind können wir unsere Einschränkung ( Num a ) in einen Typ umwandeln. Wir können dann eine neue Klasse Monad haben, die diesen Typ als Mitglied enthält (genauso wie return und fail Mitglieder sind) und es erlauben, die Beschränkung mit Num a zu überladen. So sieht der Code aus:

%Vor%

RMonad

Es gibt eine vorhandene Bibliothek namens rmonad (für "restricted monad"), die eine allgemeinere Typklasse bietet. Sie könnten dies wahrscheinlich verwenden, um Ihre gewünschte Monaden-Instanz zu schreiben. (Ich habe es selbst nicht benutzt, also ist es ein bisschen schwer zu sagen.)

Es verwendet nicht die ConstraintKinds Erweiterung und (glaube ich) unterstützt ältere Versionen von GHC. Ich denke jedoch, es ist ein bisschen hässlich; Ich bin nicht sicher, dass es die beste Option mehr ist.

Hier ist der Code, den ich mir ausgedacht habe:

%Vor%

Weiter lesen

Weitere Einzelheiten finden Sie in dieser SO-Frage .

Oleg hat einen Artikel darüber, der speziell die Set-Monade betrifft, was interessant sein könnte: "Wie schränke ich ein? Monade, ohne es zu brechen ".

Schließlich gibt es noch ein paar Artikel, die Sie auch lesen können:

Tikhon Jelvis 11.03.2014 00:36
quelle
1

Diese Antwort wird kurz sein, aber hier ist eine andere Alternative, um mit Tikhons zu gehen. Sie können eine Umwandlung der Zeichenintensität auf Ihren Typ anwenden, um grundsätzlich eine kostenlose Monade dafür zu erhalten. Verwenden Sie es einfach (im folgenden Code ist es IDnumM ) anstelle Ihres Basistyps und konvertieren Sie den endgültigen Wert am Ende in Ihren Basistyp (im folgenden Code würden Sie runIDnumM verwenden). Sie können auch Ihren Basistyp in den transformierten Typ injizieren (im folgenden Code wäre das toIDnumM ).

Ein Vorteil dieses Ansatzes besteht darin, dass er mit der Standardklasse Monad arbeitet.

%Vor%     
Jake McArthur 11.03.2014 16:52
quelle
0

Es gibt einen einfacheren Weg, dies zu tun. Man kann mehrere Funktionen verwenden. Schreiben Sie zuerst einen in die Maybe-Monade. Die Maybe-Monade gibt nichts bei Versagen zurück. Zweitens, schreibe eine Funktion, die den Just-Wert zurückgibt, wenn nicht Nothing, oder einen sicheren Wert, wenn Nothing. Drittens schreibe eine Funktion, die diese beiden Funktionen zusammensetzt.

Dies erzeugt das gewünschte Ergebnis, während es viel einfacher zu schreiben und zu verstehen ist.

    
Ian 07.04.2014 22:46
quelle

Tags und Links