如何在遍历抽象语法树时使用Reader Monad



我有一个抽象的语法树在haskell从Parsec。我希望能够查询它的结构,同时遍历它,以便将其转换为中间代码。例如,我需要知道AST的任何给定函数需要多少个参数才能进行转换。我目前正在做的是将AST传递给每个函数,这样我就可以在需要进行查找时调用它,并且我在另一个文件中有辅助函数为我进行查找。这污染了我的类型签名。尤其是当我开始添加累加器之类的东西时。

对于Reader Monad(对于不改变的状态,AST)和state Monad(对于改变的状态,累加器)来说,这将是一个很好的工作,而不是将AST传递给我听说过的每个函数。

我怎么能把最后的IO单子(gulp),并使用它在一个阅读器单子做全局查找?

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 Reader Monad进度:我把上面的例子变成了这样的东西:(见下文)。但现在我想知道,由于所有这些字符串输出的积累,我应该使用一个作家Monad ?如果是这样的话,我该如何把这两者组合起来呢?ReaderT应该封装writer吗?反之亦然?我是否应该创建一个只接受Reader和Writer的类型,而不尝试将它们组合为Monad Transformer?

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 0n"
            "constructor" -> do return "pop pointer 0nMemory.alloc 1n"
            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——用于声明

如果不了解JackDeclaration类型,很难看出如何将其转换为Reader单子。如果你的想法是在ast :: Jack对象范围内执行"映射"或"折叠",你可以写

f :: [Declaration] -> Reader Jack [Something]
f decls = mapM go decls where 
  go :: Declaration -> Reader Jack Something
  go (SubDec keyword typ subname params subbody) =
    case keyword of
      "constructor" -> do
        ast <- ask
        return (doSomething subbody ast)

,然后在上下文中使用ast作为runReader (f decls) ast执行它。

最新更新