Tôi đang viết một thông dịch viên Brainfuck trong Haskell, và tôi đã đưa ra những gì tôi tin là một mô tả rất thú vị của chương trình:Sử dụng Tiếp để có được giá trị từ tương lai và quá khứ
data Program m = Instruction (m()) (Program m)
| Control (m (Program m))
| Halt
Tuy nhiên , thật khó để phân tích một biểu diễn văn bản của một chương trình brainfuck thành kiểu dữ liệu này. Vấn đề nảy sinh khi cố gắng phân tích cú pháp dấu ngoặc vuông một cách chính xác, bởi vì có một số nút thắt buộc phải làm như vậy để kết quả vòng lặp Instruction
cuối cùng bên trong vòng lặp liên kết đến vòng lặp Control
một lần nữa.
Thông tin sơ bộ hơn một chút. Xem this version on the github repo để biết tất cả chi tiết.
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)
Đây là những gì tôi đã cố gắng:
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)
tôi figured tôi bằng cách nào đó có thể sử dụng continuations để truyền đạt thông tin từ các trường hợp '['
đến ']'
trường hợp và ngược lại, nhưng tôi không có một công ty đủ nắm bắt của Cont để thực sự làm bất cứ điều gì ngoài việc lắp ráp dự đoán hoang dã của một cái gì đó trông giống như nó có thể làm việc, như đã thấy ở trên với push
và pop
. Điều này biên dịch và chạy, nhưng kết quả là rác.
Có thể sử dụng Cont
để thắt nút thích hợp cho tình huống này không? Nếu không, thì tôi nên sử dụng kỹ thuật nào để triển khai toProgram
?
Lưu ý 1: Trước đây tôi đã gặp phải lỗi logic tinh tế: loopControl = branch is0
bị Bools đảo ngược.
Lưu ý 2: Tôi đã quản lý sử dụng MonadFix
(theo đề xuất của jberryman) với State
để đưa ra giải pháp (xem the current state of the github repository). Tôi vẫn muốn biết làm thế nào điều này có thể được thực hiện với Cont
thay thế.
Lưu ý 3: Người cố vấn Racketeer của tôi đặt a similar Racket program cùng nhau cho tôi (xem tất cả các sửa đổi). Kỹ thuật ống/đường ống của anh ta có thể được dịch sang Haskell bằng cách sử dụng Cont
không?
tl; dr tôi quản lý để thực hiện điều này bằng MonadFix, và người khác quản lý để làm điều đó bằng combinators tiếp tục vợt của. Tôi khá chắc chắn điều này có thể được thực hiện với Cont
trong Haskell. Bạn có thể chỉ cho tôi làm thế nào?
Sử dụng Sentinels để ghi lại đột biến từ những ngày trong tương lai. –
Trong tất cả các mức độ nghiêm trọng, bạn có cần sử dụng 'Cont' không? Bạn không thể đếm số hướng dẫn để nhảy, có lẽ đang thực hiện phân tích cú pháp mulit-pass, trong đó các đường thừa bổ sung số lượng lệnh để nhảy (cùng với hướng) với ''['' và '']'' nhân vật? Tức là, '[Char] -> [JumpInfo Char]' và sau đó sử dụng trình phân tích cú pháp của bạn trên kết quả, trong đó 'dữ liệu JumpInfo = JumpInfo Char (Có thể là số nguyên)'. –
Ngoài ra, bạn có thể để dữ liệu của bạn giống nhau (hoặc chủ yếu là không đưa nhiều trí tuệ vào), và vẫn sử dụng trình phân tích cú pháp 1-pass, và làm theo cách tiếp cận của người nghèo bằng cách thực hiện nó trong thời gian chạy. băng từng người một cho đến khi bạn đến đích. Trong khi điều này sẽ làm việc, nó sẽ là một bước nhảy chậm. –