Ich bin ein Gehirnfick Dolmetscher in Haskell zu schreiben, und ich kam mit dem, was ich eine sehr interessante Beschreibung eines Programms zu sein glauben:Cont Verwenden von Werten aus der Zukunft zu erwerben und die Vergangenheit
data Program m = Instruction (m()) (Program m)
| Control (m (Program m))
| Halt
jedoch Es ist schwierig, eine Textdarstellung eines Brainfuck-Programms in diesen Datentyp zu zerlegen. Das Problem tritt auf, wenn man versucht, eckige Klammern korrekt zu analysieren, weil es einige Knotenknöpfe gibt, so dass das letzte Instruction
innerhalb einer Schleife wieder mit der Control
der Schleife verknüpft wird.
Ein bisschen mehr vorläufige Informationen. Alle Details finden Sie unter this version on the github repo.
type TapeM = StateT Tape IO
type TapeP = Program TapeM
type TapeC = Cont TapeP
branch :: Monad m => m Bool -> Program m -> Program m -> Program m
branch cond trueBranch falseBranch =
Control ((\b -> if b then trueBranch else falseBranch) `liftM` cond)
loopControl :: TapeP -> TapeP -> TapeP
loopControl = branch (not <$> is0)
Hier ist, was ich versuche:
toProgram :: String -> TapeP
toProgram = (`runCont` id) . toProgramStep
liftI :: TapeM() -> String -> TapeC TapeP
liftI i cs = Instruction i <$> toProgramStep cs
toProgramStep :: String -> TapeC TapeP
toProgramStep ('>':cs) = liftI right cs
-- similarly for other instructions
toProgramStep ('[':cs) = push (toProgramStep cs)
toProgramStep (']':cs) = pop (toProgramStep cs)
push :: TapeC TapeP -> TapeC TapeP
push mcontinue = do
continue <- mcontinue
cont (\breakMake -> loopControl continue (breakMake continue))
pop :: TapeC TapeP -> TapeC TapeP
pop mbreak = do
break <- mbreak
cont (\continueMake -> loopControl (continueMake break) break)
ich dache, ich irgendwie Fortsetzungen nutzen könnte Informationen aus dem '['
Fall an den ']'
Fall und umgekehrt zu kommunizieren, aber ich habe keine feste genug Verständnis von Cont, um tatsächlich etwas zu tun, außer dem Zusammensetzen von wüsten Vermutungen von etwas, das aussieht, als könnte es funktionieren, wie oben mit push
und pop
zu sehen. Dies kompiliert und läuft, aber die Ergebnisse sind Müll.
Kann Cont
verwendet werden, um den Knoten für diese Situation geeignet zu binden? Wenn nicht, welche Technik sollte ich verwenden, um toProgram
zu implementieren?
Anmerkung 1: Ich hatte vorher einen subtilen Logikfehler: loopControl = branch is0
hatte die Bools umgekehrt.
Hinweis 2: Ich habe es geschafft, MonadFix
(wie von jberryman vorgeschlagen) mit State
, um eine Lösung zu finden (siehe the current state of the github repository). Ich würde immer noch gerne wissen, wie dies mit Cont
stattdessen getan werden könnte.
Hinweis 3: Mein Racketeer Mentor legte a similar Racket program zusammen für mich (siehe alle Revisionen). Kann seine Rohr/Rohr-Technik mit Cont
in Haskell übersetzt werden?
tl; dr ich es geschafft, dies mit MonadFix zu tun, und jemand anderes schaffte es mit Racket der Fortsetzung combinators zu tun. Ich bin mir ziemlich sicher, dass dies mit Cont
in Haskell gemacht werden kann. Kannst du mir zeigen wie?
Verwenden von Sentinels zum Erfassen von Mutanten aus vergangenen Tagen. –
In aller Ernsthaftigkeit, müssen Sie sogar 'Cont' verwenden? Könntest du nicht einfach die Anzahl der zu sprungenden Befehle zählen, vielleicht einen Multi-Pass-Parser, wo die Extra-Pässe die Anzahl der Anweisungen verbinden, die (zusammen mit der Richtung) mit den Zeichen "[" und ""] springen Figuren? Das heißt, "[Char] -> [JumpInfo Char]" und verwenden Sie dann Ihren Parser für das Ergebnis, wobei 'data JumpInfo = JumpInfo Char (Vielleicht Integer)'. –
Alternativ können Sie Ihre Daten die gleichen lassen (oder meistens, haben Sie nicht viel Intelligenz), und immer noch einen 1-Pass-Parser verwenden, und tun ein armer Mann Ansatz zur Laufzeit, wo Sie iterativ bewegen tape eins nach dem anderen, bis Sie Ihr Ziel erreichen. Während das funktionieren würde, wäre es ein langsamer Sprung. –