Ich wurde von der kürzlichen Haskell-Blog-Aktivität 1 inspiriert, meine Hand beim Schreiben eines Forth-ähnlichen DSL in Haskell auszuprobieren. Der Ansatz, den ich gewählt habe, ist gleichzeitig einfach und verwirrend:
%Vor%Für einfache Dinge funktioniert das ganz gut:
%Vor%Einfache Funktionen können trivial in ihre entsprechenden Stapeltransformationen umgewandelt werden. Das Herumspielen bringt bisher erfreuliche Ergebnisse:
%Vor%Das Problem tritt auf, wenn ich versuche, das um Funktionen höherer Ordnung zu erweitern.
%Vor% call
soll einen Stapel der Form (s :> (s :~> s'))
in die Form s
transformieren, indem die Transformation (die an der Spitze des Stapels gehalten wird) im Wesentlichen auf ihren "Rest" angewendet wird. Ich stelle mir vor, sollte so funktionieren:
Aber in Wirklichkeit gibt es mir einen großen Typ Mismatch-Fehler. Was mache ich falsch? Kann die "Stack-Transformation" -Darstellung Funktionen höherer Ordnung ausreichend handhaben oder muss ich sie anpassen?
1 NB. Im Gegensatz zu diesen Jungs, anstatt start push 1 push 2 add end
, möchte ich, dass es runF $ start (push 1) (push 2) add
ist, die Idee ist, dass ich später vielleicht eine Art Klassenmagie verwenden kann, um% code_% für bestimmte Literale implizit zu machen.
Ihr :~>
-Typ ist nicht das, was Sie wirklich wollen (daher die ImpredicativeTypes
). Wenn Sie nur den Typ Annotation von call
entfernen, funktioniert Ihre letzte Probe wie erwartet. Eine andere Möglichkeit, es zum Laufen zu bringen, ist die Verwendung weniger schicker, aber passenderer Typen mit zusätzlichen Parametern:
Aber wenn Sie nach einer netten DSL-Syntax suchen, und Sie können OverlappingInstances
tolerieren, dann können Sie sogar LiftSx-Funktionen loswerden:
Das Problem ist, dass Ihr Typ-Synonym ein polymorpher Typ ist
%Vor% Die Verwendung eines polymorphen Typs als Argument für einen Typkonstruktor, der nicht ->
ist, wird "impredicativity" genannt. Zum Beispiel wäre das folgende eine impredicative Verwendung
Aus verschiedenen Gründen ist die Schlussfolgerung mit Im prädikativität schwierig, deshalb beschwert sich GHC. (Der Name "impredicative" kommt von der Logik und dem Curry-Howard-Isomorphismus.)
In Ihrem Fall besteht die Lösung einfach darin, einen algebraischen Datentyp mit einem Konstruktor zu verwenden:
Grundsätzlich liefert der explizite Konstruktor StackArr
genügend Hinweise für die Typüberprüfung.
Alternativ können Sie auch die ImpredicativeTypes
Spracherweiterung ausprobieren.