Since ghc-8.0 we have a very nice extension called TypeApplications
. Which allows us instead of:
λ> show (5 :: Int)
"5"
do so something like that:
λ> :set -XTypeApplications
λ> show @Int 5
"5"
Which is really cool. It becomes a bit more involved when we add more type variables, but there are rules that can be used to determine the exact order, and they are very well documented:
showFooBar :: (Show a, Show b) => a -> b -> String
showFooBar a b = show a ++ " and " ++ show b
So in the function above we would first supply a
and then b
:
λ> showFooBar @Int @Double 3 4
"3 and 4.0"
That's great, but what if I'd like to change the order? No problem there, we can use ExplicitForAll
extension (or some other that imply it) to specify it:
{-# LANGUAGE ExplicitForAll #-}
showFooBar :: forall b a . (Show a, Show b) => a -> b -> String
showFooBar a b = show a ++ " and " ++ show b
And now we reversed the order of types that we are going to apply:
λ> showFooBar @Int @Double 3 4
"3.0 and 4"
The problem is that I can't seem to figure out how to achieve the same affect for functions that are part of a type class. Consider this example:
{-# LANGUAGE MultiParamTypeClasses #-}
class (Show a, Show b) => FooBar a b where
fooBarClassFunc :: a -> b -> String
I can't put forall
on a function now (eg. fooBarClassFunc :: forall a b . a -> b -> ..
, cause that changes the meaning of the function and obviously does not compile.
So, the question is, how do you change the order of type variables for the purpose of TypeApplication
inside the type class methods?
Edit
Just in case, I have tried InstanceSigs
extension, and it completely ignores the order of forall
type variables as far as TypeApplications
are concerned, which is a good thing, otherwise we would end up with behavior that is determined by the instance, rather than the class.
fooBarClassFunc'
the method, and then definefooBarClassFunc :: forall b a. ...
as a regular function. Same effect for users, a little strange for instantiators... – BackrestQuantifiedConstraints
would allow to specify this as well, but it does not seem to allow anything likeclass forall b a . (C a, C b) => K a b where
. Further, one might want the order to vary from method to method, for maximum generality. – Nickynicoclass X t where { func :: forall a b. t a -> t b -> t (a, b) }
. You just can't do it witht
, which is the type on which the typeclass is defined. Not that that helps very much... – Killdeer