Reputation: 12721
I have an ADT with two constructors; one that wraps a Double
and one that wraps an Integer
. I would like to create a function that takes a unary function on the Num
typeclass and returns a function that applies that unary function to the contents of my ADT.
I've tried this:
data X = Y Integer
| Z Double
wrap :: Num n => (n -> n) -> X -> X
wrap f (Y i) = Y $ f i
wrap f (Z i) = Z $ f i
But the compiler informs me that it can't match the type variable n
to the type Double
in the second definition of wrap
:
test.hs:5:22: error:
• Couldn't match expected type ‘n’ with actual type ‘Double’
‘n’ is a rigid type variable bound by
the type signature for:
wrap :: forall n. Num n => (n -> n) -> X -> X
at test.hs:3:9
• In the first argument of ‘f’, namely ‘i’
In the second argument of ‘($)’, namely ‘f i’
In the expression: Z $ f i
• Relevant bindings include
f :: n -> n (bound at test.hs:5:6)
wrap :: (n -> n) -> X -> X (bound at test.hs:4:1)
If I remove the second definition (so I only define wrap
on the integer constructor Y
), I get the same error, but on the first definition instead (and with actual type 'Integer'
instead of double).
If instead I remove the type signature, the first definition causes it to infer the type (Integer -> Integer) -> X -> X
for wrap, which (expectedly) causes the second definition to fail to type check.
This seems like such a simple problem that I must be missing something glaringly obvious. Thanks in advance for your help and patience!
Upvotes: 3
Views: 207
Reputation: 12721
Thanks to @user1937198, I figured out that the implicit qualification of n
was happening in the wrong scope; I was saying that I wanted to take a function that took any type that satisfied Num
and mapped that type onto the same type, when what I wanted to say was I needed a function that took all types that satisfied Num
. With RankNTypes
the code becomes:
{-# LANGUAGE RankNTypes #-}
data X = Y Integer
| Z Double
wrap :: (forall n. Num n => n -> n) -> X -> X
wrap f (Y i) = Y $ f i
wrap f (Z i) = Z $ f i
and all is good again. Thanks!
Upvotes: 4