3

識別子の型によってパラメーター化された Ast 型のコンストラクターがあります。DeriveFunctor、DeriveFoldable、および DeriveTraversable 拡張機能を使用すると、適切なインスタンスを自動的に作成できます。

より多くの型パラメーターを導入すると便利だと思いますが、残念ながら上記の方法はスケーリングしません。理想的には、Ast 型を選択型でラップして、適切な型パラメーターに fmap できるようにしたいと考えています。インスタンスを自分で定義せずに同様の効果を達成する方法はありますか?

編集:

元の Ast の外観の小さな例を次に示します。

Ast id = Ast (FuncDef id)
    deriving (Show, Functor, Foldable, Traversable)

FuncDef id = FuncDef id [Fparam id] (Block id)
    deriving (Show, Functor, Foldable, Traversable)

Block id = Block [Stmt id]
    deriving (Show, Functor, Foldable, Traversable)

..
4

1 に答える 1

1

一日中いじった後、私は次の結論に達しました:

質問で提示された Ast は、あまり柔軟ではないことが判明しました。後の段階で、元の Ast をパラメーター化するだけでは表現できない方法で、さまざまなノードに注釈を付けたいと考えています。

そこで、新しい型を書くためのベースとして機能するように、Ast を変更しました。

Ast funcdef = Ast funcdef
    deriving (Show)

Header id fpartype = Header id (Maybe Type) [fpartype]
    deriving (Show)

FuncDef header block = FuncDef header block
    deriving (Show)

Block stmt = Block [stmt]
    deriving (Show)

Stmt lvalue expr funccall = 
    StmtAssign lvalue expr |
    StmtFuncCall funccall |
    ..

Expr expr intConst lvalue funccall =
    ExprIntConst intConst |
    ExprLvalue lvalue |
    ExprFuncCall funccall |
    expr :+ expr |
    expr :- expr |
    ..

これで、各コンパイラ ステージに対して一連の newtype を簡単に定義できるようになりました。リネームの段階での Ast は、識別子の型を中心にパラメーター化できます。

newtype RAst id = RAst { ast :: Ast (RFuncDef id) }
newtype RHeader id = RHeader { header :: Header id (RFparType id) }
newtype RFuncDef id = RFuncDef { 
    funcDef :: FuncDef (RHeader id) (RBlock id) 
}
..
newtype RExpr id = RExpr { 
    expr :: Expr (RExpr id) RIntConst (RLvalue id) (RFuncCall id) 
}

型チェックの段階で、Ast はノードで使用されるさまざまな内部型によってパラメーター化される場合があります。

Maybeこのパラメーター化により、各ステージの途中でラップされたパラメーターを使用して Ast を構築できます。

すべて問題なければfmap、s を削除してMaybe、ツリーを次の段階に向けて準備することができます。他Functor, FoldableTraversableも便利な方法がありますので、これらは必須です。

この時点で、私が望むことはメタプログラミングなしでは不可能である可能性が高いと考えたので、テンプレート Haskell ソリューションを探しました。確かに、ジェネリックと関数を実装するgenifunctorsライブラリが あります。これらを使用すると、いくつかの newtype ラッパーを記述して、適切なパラメーターの周りに必要な型クラスのさまざまなインスタンスを作成するだけです。fmap, foldMaptraverse

fmapGAst = $(genFmap Ast)
foldMapGAst = $(genFoldMap Ast)
traverseGast = $(genTraverse Ast)

newtype OverT1 t2 t3 t1 = OverT1 {unwrapT1 :: Ast t1 t2 t3 }
newtype OverT2 t1 t3 t2 = OverT2 {unwrapT2 :: Ast t1 t2 t3 }
newtype OverT3 t1 t2 t3 = OverT3 {unwrapT3 :: Ast t1 t2 t3 }

instance Functor (OverT1 a b) where
    fmap f w = OverT1 $ fmapGAst f id id $ unwrapT1 w

instance Functor (OverT2 a b) where
    fmap f w = OverT2 $ fmapGAst id f id $ unwrapT2 w

instance Functor (OverT3 a b) where
    fmap f w = OverT3 $ fmapGAst id id f $ unwrapT3 w

..
于 2017-06-06T05:35:08.630 に答える