Ambiguous type variable
Related to my earlier question on traversing data structures, I'm having a problem making my code generic when I use it along with the uniplate package. I'm dealing with the data structures in the Language.Exts.Annotated.Syntax module, which are all generic with a type parameter l
. This l
is the same throughout the tree.
The kind of code I'm writing is like this:
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
This code produces the following error on both o开发者_StackOverflow社区f the last two lines:
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)
I can see why this code is ambiguous: transformBi
accepts a (to -> to)
and from
and turns it into a from
; in my case there's no link between the l
in Child1 l
and the l
in Parent l
. What I don't see is how to fix it. I've tried adding a type constraint like transformBi (doInt :: Child1 l -> Child1 l)
, but I get the same error; it's as if I'm introducing a new l
when I do this.
How can I tell the compiler that I'm using the same l
for replace
, transformBi doInt
and transformBi doString
?
Edit: Here is the full program that demonstrates what I'm doing. Under GHC 6.10.4, this program fails to compile, with the above error.
It looks like you need the scoped type variables extension.
{-# LANGUAGE ScopedTypeVariables #-}
replace :: forall l. Data l => Parent l -> Parent l
replace = transformBi (doInt :: Child1 l -> Child1 l)
. transformBi (doString :: Child2 l -> Child2 l)
Note that quantification must be explicit to bring l
into scope.
l
should be of same type in function replace
:
Define it like:
data L = LInt Integer| LString String
See, replace
can't be a polymorphic function. It uses strict types. This types defined by operations:
Prelude> :t (+)
(+) :: (Num a) => a -> a -> a
and
Prelude> :t (:)
(:) :: a -> [a] -> [a]
and
Prelude> :t 'c'
'c' :: Char
To make replace polymorphic you have to make it of polymorphic functions.
精彩评论