12

parsecライブラリを使用して(学習目的で)haskellに単純なパーサーを実装しようとしています。そこで、次のような一連のデータ構造と関連する関数を作成しました。

data SourceElement 
    = StatementSourceElement Statement
    | FunctionSourceElement FunctionName FunctionBody

data Statement 
    = IfStatement Expr Statement Statement
    | WhileStatement Expr Statement

data FunctionBody = FunctionBody [SourceElement]

parseSourceElement :: Parser SourceElement
parseSourceElement = ...

parseFunctionBody :: Parser FunctionBody
parseFunctionBody = ...

それは正常に動作します。ここで、これを 2 つのモジュールに分割して、データ構造を分離したいと考えていますFunctionBody(Statement読みやすさの問題のため)。しかし、私はできません!その理由は、SourceElementとの間の循環依存FunctionBodyです。

それで、この問題を解決する方法はありますか?

4

2 に答える 2

13

依存関係のサイクルを断ち切る典型的な方法は、何かをパラメータ化することです。この場合、Functionモジュールは言語の関数パーサーを実行する可能性がありますが、言語の残りの部分がどのようなものであっても実行できるように表現されています。したがって:

module Function where 

data FunctionBody e = FunctionBody [e]

parseFunctionBody :: Parser e -> Parser (FunctionBody e)

module AST where

data SourceElement
    = StatementSourceElement Statement
    | FunctionSourceElement FunctionName (FunctionBody SourceElement)

したがって、相互再帰は、単純な再帰 + パラメータ化に抽象化されます。パラメータ化は、少なくとも異なるものを異なるファイルに分離するのと同じくらい重要だと思います。

于 2012-12-09T15:20:22.493 に答える
6

Haskellは実際には再帰モジュールを許可しており、GHCはそれらをサポートしています(ファイルの書き込みに少し不便があり.hs-bootます)。相互再帰モジュールをコンパイルする方法を参照してください。

ここでこの機能を使用しても問題はありません。

于 2012-12-09T16:39:35.703 に答える