与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下,该程序无法编译,出现上述错误。
最佳答案
看来您需要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
纳入范围。