How can I get the type of polymorphic function for a specific instance of a class class?

For example, input :t ap in GHCi gives the result

 ap :: Monad m => m (a -> b) -> ma -> mb 

If I already know that the Monad instance I'm going to use is ((->) r) , how can I request the ap type for this particular instance?

+6
haskell ghci lambdabot
source share
3 answers

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.

+10
source share

As Lazersmoke , you can use the TypeApplications extension that was introduced in GHC 8.0 as a comment.

In GHCi:

 λ > :set -XTypeApplications λ > import Control.Monad λ > :t ap @((->) _) ap @((->) _) :: (t -> a -> b) -> (t -> a) -> t -> b 
+12
source share

This is just a hack, but you can always do something like:

 :t ap . (id :: ((->) ra) -> ((->) ra)) 

or

 :t \xy -> (id :: ...) (ap xy) 

Interestingly

 Prelude Control.Monad> type Reader = (->) r Prelude Control.Monad> :t ap . (id :: Reader ra -> Reader ra) ap . (id :: Reader ra -> Reader ra) :: Reader r (a -> b) -> (r -> a) -> r -> b 

differs from

 Prelude Control.Monad> :t \xy -> (id :: Reader ra -> Reader ra) (ap xy) \xy -> (id :: Reader ra -> Reader ra) (ap xy) :: (r -> a1 -> a) -> (r -> a1) -> Reader ra 

that the GHC recognizes as a synonym for Reader ra

+2
source share

All Articles