3

我之前关于遍历数据结构的问题相关,当我将代码与 uniplate 包一起使用时,我遇到了使代码通用的问题。我正在处理Language.Exts.Annotated.Syntax模块中的数据结构,它们都是具有类型参数的泛型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

此代码在最后两行都产生以下错误:

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)

我可以理解为什么这段代码是模棱两可的:transformBi接受 a(to -> to)并将from其转换为from; l就我而言, inChild1 llin之间没有联系Parent l。我没有看到如何解决它。我尝试添加类似的类型约束transformBi (doInt :: Child1 l -> Child1 l),但我得到了同样的错误;l当我这样做时,就好像我正在引入一个新的。

如何告诉编译器我lreplace,transformBi doInt和使用相同的transformBi 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 回答