与my earlier question on traversing data structures相关,我在将代码与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
接受(to -> to)
和from
并将其转换为from
;就我而言,l
中的Child1 l
与l
中的Parent l
之间没有任何关联。我没看到的是如何解决它。我尝试添加像transformBi (doInt :: Child1 l -> Child1 l)
这样的类型约束,但我得到了同样的错误;这就好像我在做这个时引入一个新的l
。
如何告诉编译器我对l
,replace
和transformBi doInt
使用相同的transformBi doString
?
修改: Here is the full program that demonstrates what I'm doing。在GHC 6.10.4下,由于上述错误,该程序无法编译。
答案 0 :(得分:9)
您似乎需要scoped type variables扩展名。
{-# 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
纳入范围。
答案 1 :(得分: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
要使替换多态,你必须使其具有多态函数。