3

データ構造のトラバースに関する以前の質問に関連して、ユニプレートパッケージと一緒に使用すると、コードを汎用化するのに問題があります。私はLanguage.Exts.Annotated.Syntaxモジュールのデータ構造を扱っています。これらはすべてtypeパラメーターを持つ汎用lです。これlはツリー全体で同じです。

私が書いているコードの種類は次のようなものです。

doInt :: Child1 l -> Child1 l
doInt (Child1 l n) = Child1 l (n + 1)

doString :: Child2 l -> Child2 l
doString (Child2 l (_:s)) = Child2 l ('j' : s)

replace :: Data l => Parent l -> Parent l
replace = transformBi doInt
        . transformBi doString

このコードは、最後の2行の両方で次のエラーを生成します。

Ambiguous type variable `l' in the constraint:
  `Data l' arising from a use of `transformBi' at Test.hs:31:10-52
Probable fix: add a type signature that fixes these type variable(s)

このコードがあいまいである理由がわかります。aをtransformBi受け入れて;に変換します。私の場合、inとinの間にリンクはありません。私が見ないのはそれを修正する方法です。のような型制約を追加しようとしましたが、同じエラーが発生します。これを行うと、まるで新しいものを紹介しているようです。(to -> to)fromfromlChild1 llParent ltransformBi (doInt :: Child1 l -> Child1 l)l

、およびに同じlものを使用していることをコンパイラに伝えるにはどうすればよいですか?replacetransformBi doInttransformBi doString

編集: これは私がしていることを示す完全なプログラムです。GHC 6.10.4では、このプログラムはコンパイルに失敗し、上記のエラーが発生します。

4

2 に答える 2

9

スコープ型変数拡張が必要な​​ようです。

{-# LANGUAGE ScopedTypeVariables #-}

replace :: forall l. Data l => Parent l -> Parent l
replace = transformBi (doInt :: Child1 l -> Child1 l)
        . transformBi (doString :: Child2 l -> Child2 l)

数量化は、範囲に含めるために明示的でなければならないlことに注意してください。

于 2009-12-08T11:01:46.543 に答える
0

l関数内で同じ型にする必要がありますreplace: 次のように定義します:

data L = LInt Integer| LString String

ほら、replace多態的な関数にすることはできません。厳密な型を使用します。操作によって定義されるこのタイプ:

Prelude> :t (+)
(+) :: (Num a) => a -> a -> a

Prelude> :t (:)
(:) :: a -> [a] -> [a]

Prelude> :t 'c'
'c' :: Char

置換をポリモーフィックにするには、それをポリモーフィック関数にする必要があります。

于 2009-12-08T08:17:53.127 に答える