私は、これは真実ではありませんHaskellの
でどこでも任意のグローバルデータを保存することはできません。ほとんどの場合、State monadのようなもので十分ですが、ST monadもあります。
ただし、このタスクではグローバルな状態は必要ありません。パーサーの記述は2つの部分で構成されています。字句解析と構文解析が含まれます。字句解析は、文字ストリームを意味のあるトークンストリームに変換するだけです。構文解析により、トークンがASTに変換されます。これはインデントに対処すべき場所です。
インデントを解釈するときに、インデントレベルの変更に応じてハンドラ関数を呼び出すことができます。ネスティングが増加すると、ハンドラ関数を呼び出します(インデントを追跡する場合は、1つのargをインクリメントします)レベル);レベルが減少すると、関連するAST部分が関数から返されます。
(大域変数を使用すると、命令型言語では私には起こりえない何かがありますが、それがインスタンス変数です。ステートモナドはこれと概念的に非常に似ています)
最後に、私は「私のレキシングルールをすべてのモナドの中に入れることはできません」という表現は、モナドの何らかの誤解を示していると思います。代わりに(.)
または($)
と機能のアプリケーションを組み合わせる
data AST = ...
type Step = State Int AST
parseFunction :: Stream -> Step
parseFunction s = do
level <- get
...
if anotherFunction then put (level + 1) >> parseFunction ...
else parseWhatever
...
return node
parse :: Stream -> Step
parse s = do
if looksLikeFunction then parseFunction ...
main = runState parse 0 -- initial nesting of 0
、あなたが(>>=)
または(>>)
と組み合わせる:私が解析し、グローバルな状態を維持するために必要な場合は、私のコードは次のようになります。それ以外のアルゴリズムは同じです。あなたは "funcallの" のようなものを持っている場合
eval :: Environment -> Node -> Evaluated
eval e (Constant x) = Evaluated x
eval e (Variable x) = Evaluated (lookup e x)
eval e (Function f x y) = (f <$> (`eval` x) <*> (`eval` y)) e
(または
eval e (Function f x y) = ((`eval` f) <*> (`eval` x) <*> (`eval` y)) e
:(。 "内部" すべき "モナド" はありません)
最後に、あなたは応用的ファンクタを好むかもしれません...しかし、私は逃げます。)
アプリケーションファンクタ、モナド、および矢印を使って解析することに関する文献はたくさんあります。これらのすべてがあなたの問題を解決する可能性を秘めています。それらを読んで、あなたが得るものを見てください。
ニース。私はAlexとちょっと遊んでしまい、PArrows(これは通常私が手に入れているもの)よりもいくつかの点でよりクリーンであることがわかりました。情報ありがとうございました:) – jrockway
ああ、ありがとう。私は#haskellでも尋ねましたが、alexのUserStateラッパーを発見しました。しかしそれほど多くのドキュメントはありませんでしたが、いくつかのソースハンティングをしなければなりませんでした。 私は国家のモナドについて知っていますが、私はアレックスのレクサーを通してスレッドの状態について不明でした。 ありがとうございます。 – kamatsu