7

Parsec から作成された Haskell の抽象構文ツリーがあります。中間コードに変換するために、同時にトラバースしながらその構造を照会できるようにしたいと考えています。たとえば、AST の任意の関数がこの変換を行うために必要なパラメーターの数を知る必要があります。私が現在行っていることは、すべての関数に AST を渡すことです。これにより、ルックアップを行う必要があるときはいつでも AST を呼び出すことができ、別のファイルにルックアップを行うためのヘルパー関数があります。これは私の型シグネチャを汚染しています。特に、アキュムレータのようなものを追加し始めたとき.

私が聞いたすべての関数に AST を渡す代わりに、これは Reader モナド (変化しない状態の場合は AST) と State モナド (変化する状態の場合はアキュムレータ) に適していると聞いています。

IO モナド ( gulp )から ast を取り出し、それを Reader モナドで使用してグローバル ルックアップを行うにはどうすればよいですか?

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 -> []

Reader Monad の進行状況に関する更新: 上記の例を次のように変換しました: (以下を参照)。しかし、文字列出力が蓄積されているため、ライター Monad も使用する必要があるのではないかと考えています。もしそうなら、私はどのように2つの曲を作るべきですか? ReaderT はライターをカプセル化する必要がありますか? またはその逆?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 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 --宣言用

4

1 に答える 1

1

Jackand型についてもう少し知らなければ、Declarationそれを 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次に、 asのコンテキストで実行しますrunReader (f decls) ast

于 2013-03-06T16:28:25.603 に答える