0

私は現在、Haskellに埋め込まれた構文のような(一種の)typesafexmlを作成しようとしています。結局、私はこのようなことを達成したいと思っています:

tree = group [arg1 "str", arg2 42] 
         [item [foo, bar] []
         ,item [foo, bar] []
         ]

ここで、グループとアイテムは種類がありNode :: [Arg t] -> [Node c] -> Node tます。これが意味をなさない場合は、おそらく私が何をしているのかわからないためです:)

今の私の質問は、型システムがに「間違った」引数を与えるのを防ぐ方法ですNode。たとえばNode、型のsは型のGroup引数のみを持つことができますが、sは型Arg1との引数を持つことができます。Arg2ItemFooBar

肝心な質問は、異種リストのタイプをどのように制限するかということだと思います。


私が達成しようとしている(ユーザー)構文の例:

group .: arg1 "str" .: arg2 42
    item .: foo .: bar
    item .: foo .: bar

ここで、(。:)は、ノードにパラメーターを設定する関数です。これは、2つのアイテムを含むいくつかのパラメーターを持つグループを表します。

さらに、次のような(疑似)定義があります。

data Node = Node PossibleArguments PossibleChildNodes

type Group = Node [Arg1, Arg2] [Item]
type Item  = Node [Foo, Bar] []

タイプチェッカーで使用エラーをキャッチする方法を探しています。

4

2 に答える 2

3

あなたが持っているものは、異種のリストが必要なようには思えません。多分あなたはこのようなものを探していますか?

data Foo = Foo Int

data Bar = Bar Int

data Arg = StringArg String | IntArg Int | DoubleArg Double

data Tree = Group Arg Arg [Item]

data Item = Item Foo Bar

example :: Tree
example = Group (StringArg "str") (IntArg 42)
            [Item (Foo 1) (Bar 2), Item (Foo 12) (Bar 36)]

Arg異なる「サブタイプ」の のリストを作成することもできることに注意してください。たとえば、[StringArg "hello", IntArg 3, DoubleArg 12.0]. ただし、それでも同種のリストになります。

=====編集=====

「デフォルトの引数」の状況を処理する方法はいくつかあります。アイテムのBar引数がオプションであるとします。私の最初の考えは、ユーザーが指定するのはオプションかもしれないが、データを保存するときにデフォルトの引数を含めたいということです。そうすれば、デフォルトの決定は、実際に何かを行うコードから分離されます。したがって、ユーザーが aFooの 3 を指定し、a を指定せずBar、デフォルトがBar 77である場合、次のようにアイテムを作成します。

Item (Foo 3) (Bar 77)

これには、このオブジェクトを操作する関数がデフォルトを気にする必要がないという利点があります。関係する限り、両方のパラメーターが常に存在します。

ただし、データ構造でデフォルトの引数を本当に省略したい場合は、次のようにすることができます。

data Bar = Bar Int | DefaultBar

example = Group (StringArg "str") (IntArg 42)
            [Item (Foo 1) (Bar 2), Item (Foo 12) DefaultBar]

あるいは:

data Item = Item Foo Bar | ItemWithDefaultBar Foo

===== 編集 #2 =====

したがって、おそらく次のようなものを使用できます。

data ComplicatedItem = ComplicatedItem 
    {
      location :: (Double, Double),
      size :: Int,
      rotation :: Double,
      . . . and so on . . .
    }

defaultComplicatedItem = ComplicatedItem { location = (0.0,0.0), size = 1, rotation = 0.0), ... }

を作成するComplicatedItemには、ユーザーはデフォルト以外のパラメーターを指定するだけです。

myComplicatedItem = defaultComplicatedItem { size=3 }

型に新しいパラメーターを追加する場合ComplicatedItem、 を更新する必要がありますdefaultComplicatedItemが、 の定義myComplicatedItemは変更されません。

show印刷時にデフォルトのパラメーターを省略するように関数をオーバーライドすることもできます。

于 2013-01-15T13:55:22.283 に答える
1

その後の議論に基づくと、XML を表現するために DSL (ドメイン固有言語) を作成する必要があるように思えます。

1 つのオプションは、DSL を Haskell に埋め込んで、Haskell ソース コードに表示できるようにすることです。一般に、これを行うには、必要な型を定義し、それらの型を操作する一連の関数を提供します。これがあなたが望んでいることのように聞こえます。ただし、組み込みDSL として、いくつかの制約が課せられます。これがあなたが直面している問題です。おそらく、あなたが望むことを行うための巧妙なトリック、おそらく型関数を含むものがあるでしょうが、現時点では何も思いつきません。試してみたい場合は、タグdslを追加gadtして質問に追加し、私よりもこのことについてよく知っている人の注意を引いてください。あるいは、 Template Haskellのようなものを使用できるかもしれません または、Boilerplateをスクラップして、Haskell が「見る」前にユーザーが「記入」する情報をユーザーが省略できるようにします。

別のオプションは、Haskell を使用して解析する外部 DSL を持つことです。DSL を定義することもできますが、適切な DTD で XML を直接使用する方が簡単かもしれません。もちろん、XML を解析するための Haskell ライブラリがあります。

于 2013-01-17T13:04:15.003 に答える