I tried this:
type TestT = Either Int Float
testM :: (a -> a) -> TestT -> TestT
testM f (Left x) = Left (f x)
testM f (Right x) = Right (f x)
but it doesn't work, is there any way to do this? I did some looking around and everything similar was really complicated and limited.
Error message, as requesed:
Main.hs:101:28: error:
• Couldn't match expected type ‘a’ with actual type ‘Int’
‘a’ is a rigid type variable bound by
the type signature for:
testM :: forall a. (a -> a) -> TestT -> TestT
at Main.hs:100:1-35
• In the first argument of ‘f’, namely ‘x’
In the first argument of ‘Left’, namely ‘(f x)’
In the expression: Left (f x)
• Relevant bindings include
f :: a -> a (bound at Main.hs:101:7)
testM :: (a -> a) -> TestT -> TestT (bound at Main.hs:101:1)
I don't think you can do that in the base language. As mentioned in the comments, you might need to enable a couple of extensions, such as RankNTypes.
As all involved types are numeric ones, it is tempting to use an increment function, such as (+1) as the polymorphic function.
Let's try under
ghci
:Note 1: If you omit the language extensions, it breaks, with a message hinting to RankNTypes.
Note 2: If you use
forall a. Num a => (a -> a)
instead of(forall a. Num a => a -> a)
, it also breaks.Note 3: Some prior art here: SO-q38298119 with a useful comment from Alexis King.