Tôi có một cây cú pháp trừu tượng trong haskell được tạo từ Parsec. Tôi muốn có thể truy vấn cấu trúc của nó trong khi di chuyển nó cùng một lúc để dịch nó thành mã trung gian. Ví dụ, tôi cần phải biết có bao nhiêu tham số mà bất kỳ hàm nào của AST của tôi đã đưa ra để thực hiện bản dịch này. Những gì tôi hiện đang làm là truyền AST vào mọi chức năng duy nhất để tôi có thể gọi nó bất cứ khi nào tôi cần tra cứu và tôi có chức năng trợ giúp trong một tệp khác để thực hiện tra cứu cho tôi. Điều này gây ô nhiễm chữ ký của tôi. Đặc biệt là khi tôi bắt đầu thêm nhiều thứ hơn như một bộ tích lũy.Cách sử dụng Reader Monad khi duyệt qua một cây cú pháp trừu tượng
Thay vì chuyển qua AST cho mọi chức năng tôi đã nghe, đây sẽ là một công việc tốt cho Reader Monad (cho trạng thái không thay đổi, AST) và State Monad (trạng thái thay đổi, bộ tích lũy).
Làm thế nào tôi có thể lấy ast ra khỏi đơn nguyên IO (gulp) và sử dụng nó trong Reader Monad để thực hiện tra cứu toàn cầu?
main = do
putStrLn "Please enter the name of your jack file (i.e. Main)"
fileName <- getLine
file <- readFile (fileName++".jack")
let ast = parseString file
writeFile (fileName++".xml") (toClass ast) --I need to query this globally
putStrLn $ "Completed Parsing, " ++ fileName ++ ".vm created..."
type VM = String
toClass :: Jack -> VM
toClass c = case c of
(Class ident decs) ->
toDecs decs
toDecs ::[Declaration] -> VM -- I don't want to add the ast in every function arg...
toDecs [] = ""
toDecs (x:xs) = case x of
(SubDec keyword typ subname params subbody) ->
case keyword of
"constructor" -> --use the above ast to query the # of local variables here...
toSubBody subbody ++
toDecs xs
otherwise -> []
UPDATE on Reader Tiến trình đơn nguyên: Tôi đã chuyển ví dụ trên thành một dạng như sau: (xem bên dưới). Nhưng bây giờ tôi đang tự hỏi vì tất cả sự tích tụ chuỗi đầu ra này, tôi có nên sử dụng một nhà văn Monad không? Và nếu có, tôi nên làm thế nào để sáng tác cả hai? Nên ReaderT đóng gói nhà văn? hoặc ngược lại? Tôi có nên tạo một loại chỉ chấp nhận một Reader và một Writer mà không cố gắng tạo chúng như một Biến Áp Monad không?
main = do
putStrLn "Please enter the name of your jack file (i.e. Main)"
fileName <- getLine
file <- readFile (fileName++".jack")
writeFile (fileName++".xml") (runReader toClass $ parseString file)
putStrLn $ "Completed Parsing, " ++ fileName ++ ".xml created..."
toClass = do
env <- ask
case env of Class ident decs -> return $ toDecs decs env
toDecs [] = return ""
toDecs ((SubDec keyword typ subname params subbody):xs) = do
env <- ask
res <- (case keyword of
"method" -> do return "push this 0\n"
"constructor" -> do return "pop pointer 0\nMemory.alloc 1\n"
otherwise -> do return "")
return $ res ++ toSubBody subbody env ++ toDecs xs env
toDecs (_:xs) = do
decs <- ask
return $ toDecs xs decs
toSubBody (SubBodyStatement states) = do
return $ toStatement states
toSubBody (SubBody _ states) = do
return $ toStatement states
http://hpaste.org/83595 tờ khai --cho
Bạn đã tìm thấy một cơ hội rất thích hợp để sử dụng trình đơn đọc. Thật vậy, bạn không muốn truyền xung quanh AST mọi lúc. Tuy nhiên, trong mã mẫu của bạn, tôi không thể thấy bất kỳ hàm nào (và tôi mong đợi nhiều) tham gia vào một AST. Có thể bạn có thể dán mã với ít chi tiết hơn về miền của mình? – Tarrasch
Tarrasch, một ví dụ sẽ là trường hợp "hàm tạo". Kết quả của nó cần phải là: "push pointer" ++ (hiển thị $ getFieldCount subname ast) ++ "\ n" Tôi có nó được nêu trong đoạn mã trên. –
trong 'toDecs' bạn ràng buộc' res', nhưng không bao giờ sử dụng nó. Tôi không chắc đó có phải là một sai lầm hay một lỗi đánh máy. Ngoài ra, loại 'toDecs' là gì? Trong 2 trường hợp đầu tiên, phải mất 1 đầu vào, nhưng trong trường hợp thứ 3, cần có 2. Sẽ dễ dàng hơn nếu bạn cung cấp đoạn mã biên dịch (ví dụ: với định nghĩa dữ liệu cho 'Lớp',' SubDec' , 'SubBody' vv ...) – cdk