9

私はLanguage.Exts.Annotated.Syntaxからの値を処理するコードを書いています。ここでは、Haskellモジュールの構造を反映するさまざまなタイプが定義されています。

data Module l = ...
data Decl l = ...
data Exp t = ...
-- etc

これらのデータ構造をウォークし、さまざまな変換を実行する関数を記述できるようにしたいと思います。共通のデータ型が1つもないため、すべてを実行する1つの関数を作成することはできません。

これまでのところTree、変換関数が実行できるように、これらの各型をラップする型を作成しましたTree l -> Tree l

data Tree l = ModuleT (Module l)
            | DeclT (Decl l)
            | ExpT (Exp l)
            -- etc copy & paste

しかし、私は今、を取り、ModuleそれをラップしModuleT、関数を呼び出し、そして結果をModule再びアンラップする多くのコードを書いていることに気づいています。私は持っています:

class AnnotatedTree ast where
  tree :: ast l -> Tree l
  untree :: Tree l -> ast l

instance AnnotatedTree Module where
  tree = ModuleT
  untree (ModuleT x) = x
  untree _ = error "expected ModuleT"

-- etc ad nauseam

2つの質問:

  1. Language.Exts.Annotated.Syntaxの型を変更できないことを考えると、これは間違った方法で行っているのでしょうか。
  2. そうでない場合は、この定型文をなんとかして削減できますか?
4

1 に答える 1

6

これらのタイプはすべて、TypeableとDataのインスタンスのようです。タイプTreeをTypeableとDataのインスタンスとして定義し、利用可能なジェネリックライブラリ(SYB、uniplateなど)の1つを使用して、ツリーを簡単にトラバースできます。

私の個人的なお気に入りはユニプレートです。たとえば、TreeからすべてのGuardedAltを収集するのは、次のように簡単です。

import Data.Uniplate.PlateData

...

allGuardedAlts :: Tree l -> [l]
allGuardedAlts t = [ l | GuardedAlt l _ _ <- universeBi t]

私が同じようなことをした私のパッケージグラフタイプを見ることができます。

于 2009-12-06T19:05:31.627 に答える