On Sat, Dec 31, 2011 at 4:09 PM, Kevin Quick
<quick@sparq.org> wrote:
onVarElem :: forall a . (Show a) => (Maybe a -> String) -> Var -> String
onVarElem f (V1 x) = f x
onVarElem f (V2 x) = f x
main = putStrLn . onVarElem elemStr $ test
This is probably a better design, but still fails for the same reason:
Couldn't match expected type `Int' with actual type `[Char]'
Expected type: Maybe Int
Actual type: Maybe String
In the first argument of `f', namely `x'
In the expression: f x
The problem is the scope of the quantification of the type variable 'a'. You can use higher-rank types (via the Rnak2Types or RankNTypes language extension) to achieve what you want. Change the type of 'onVarElem' to
onVarElem :: (forall a . (Show a) => Maybe a -> String) -> Var -> String
In contrast to the previous type, this type says that the provided function must be polymorphic over Show instances 'a', while the previous type would have allowed any specialization of 'a' with a Show instance.
With the previous type, the call
onVarElem (maybe show (show . not))
would have been legal, with the new type it is not, which is necessary for the implementation to be well typed.
If you don't want to use a language extension that allows you to require polymorphism on function arguments, then Stephen's solution is a good workaround.
Sebastian