You can use the prominent type function to specify parametric types. You can look at functions more creatively: functions in Haskell can be applied not only to values of certain types, but also to types of these values. But in order to pass a type, you must somehow indicate (with the addition of @ ) that you are passing types (since types are not first-class objects in Haskell yet).
So how does it work:
λ: :set -XTypeApplications λ: :t ap @((->) Int) ap @((->) Int) :: (Int -> a -> b) -> (Int -> a) -> Int -> b
The only limitation of this approach is that you cannot use type variables in ghci , you must use certain types ( Int instead of r ), but that doesn't really matter.
ADDITIONAL SECTION
Well, actually you can, but it's hard:
λ: :set -XExplicitForAll λ: :set -XPartialTypeSignatures λ: :set -XScopedTypeVariables λ: :{ λ| foo :: forall r . _ λ| foo = ap @((->) r) λ| :} <interactive>:28:19: warning: [-Wpartial-type-signatures] • Found type wildcard '_' standing for '(r -> a -> b) -> (r -> a) -> r -> b' λ: :t foo foo :: (r -> a -> b) -> (r -> a) -> r -> b
UPD:. Instead of actual variables, you can use placeholders instead (see another answer ). But if you want to specify the exact names, use the approach above.
λ: :t ap @((->) _) ap @((->) _) :: (t -> a -> b) -> (t -> a) -> t -> b
/ ADDITIONAL SECTION
One more thing to say about this approach: you have to do something else if your functions have several type parameters and you want to specify the exact one. Types are passed one by one from left to right as simple arguments in some function of the type bar :: Int -> String -> Double . If you want to fix the first argument of bar , you must write bar 5 , and if you want to fix the second, then you can write something like \n -> bar n "baz" , but this does not work with the application type. You need to know two things:
- Type order.
- How to specify the desired type.
Consider the following function:
λ: :t lift lift :: (Monad m, MonadTrans t) => ma -> tma
We want to be able to specify variables of type m and t . Since Haskell does not have type variables of type (yet), you cannot write :t lift {t=MaybeT} or :t lift {m=IO} unfortunately. So, back to two things.
To view the type order, you must use some compiler options. The order of the type arguments is specified by forall , and you can do it manually. Otherwise, the type parameters will be sorted in some way by the compiler. Mortals cannot see the type order for the lift function, but if you know about high-level magic, you can:
λ: :set -fprint-explicit-foralls λ: :t lift lift :: forall {t :: (* -> *) -> * -> *} {a} {m :: * -> *}. (Monad m, MonadTrans t) => ma -> tma
And then you should use @_ to skip some types:
λ: :t lift @MaybeT lift @MaybeT :: forall {a} {m :: * -> *}. Monad m => ma -> MaybeT ma λ: :t lift @_ @IO lift @_ @IO :: forall {t :: (* -> *) -> * -> *} {a}. MonadTrans t => IO a -> t IO a λ: :t lift @_ @_ @Int lift @_ @_ @Int :: forall {t :: (* -> *) -> * -> *} {t1 :: * -> *}. (Monad t1, MonadTrans t) => t1 Int -> t t1 Int
Well, for me it's really a mystery why m shown as the third argument in forall , but should be passed as the second, but I still don't know all the magic.