For example, typing :t ap
in GHCi gives the result
ap :: Monad m => m (a -> b) -> m a -> m b
If I already know the Monad instance I'm going to use is ((->) r)
, how can I query for the type of ap
for that specific instance?
Polymorphism in Java 1 Compile-time polymorphism: It is also known as static polymorphism. This type of polymorphism is achieved by function... 2 Runtime polymorphism: It is also known as Dynamic Method Dispatch. It is a process in which a function call to the... More ...
Examples of used defined polymorphic functions : def add (x, y, z = 0): return x + y+z. print(add (2, 3)) print(add (2, 3, 4)) Output: 5 9. Polymorphism with class methods: Below code shows how python can use two different class types, in the same way.
More specifically, it is the ability of a program to process objects differently depending on their data type or class. Compile-time Polymorphism − This type of polymorphism can be achieved using method overloading. Run-time Polymorphism − This type of polymorphism can be achieved using method overriding and virtual functions.
Functional Programming - Polymorphism. Polymorphism, in terms of programming, means reusing a single code multiple times. More specifically, it is the ability of a program to process objects differently depending on their data type or class. Compile-time Polymorphism − This type of polymorphism can be achieved using method overloading.
As Lazersmoke said as a comment you can use the TypeApplications extension that was introduced in GHC 8.0.
In GHCi:
λ > :set -XTypeApplications
λ > import Control.Monad
λ > :t ap @((->) _)
ap @((->) _) :: (t -> a -> b) -> (t -> a) -> t -> b
You can use visible type application feature to specify parametric types. You can look at functions in more creative way: functions in Haskell can be applied to not only values of some types, but also to types of that values. But to pass type you should somehow specify (with prepending @
) that you're passing types (because types are not first-class objects in Haskell yet).
So here how it works:
λ: :set -XTypeApplications
λ: :t ap @((->) Int)
ap @((->) Int) :: (Int -> a -> b) -> (Int -> a) -> Int -> b
The only limitation of such approach is that you can't use type variables in ghci
, you should use specific types (Int
instead of r
) but this is not big deal.
ADVANCED SECTION
Well, actually you can, but it's tricky:
λ: :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: You can actually use placeholders instead of type variables (see another answer). But if you want to specify exact names use approach from above.
λ: :t ap @((->) _)
ap @((->) _) :: (t -> a -> b) -> (t -> a) -> t -> b
/ADVANCED SECTION
One more thing to say about this approach: you should do something more if your functions have several type parameters and you want to specify exact one. Types are passed one by one from left to right just as simple arguments in some function like bar :: Int -> String -> Double
. If you want to fix first argument of bar
you should write bar 5
and if you want to fix second, then, well, you can write something like \n -> bar n "baz"
but this doesn't work with type application. You need to know two things:
Consider next function:
λ: :t lift
lift :: (Monad m, MonadTrans t) => m a -> t m a
We want be able to specify m
and t
type variables. Because Haskell has no named type variables (yet) you can't write :t lift {t=MaybeT}
or :t lift {m=IO}
unfortunately. So go back to two things.
To see order of types you should use some compiler options. Order of type arguments is specified by forall
and you can do it manually. Otherwise type parameters will be sorted somehow by the compiler. Mere mortals can't see order of types for lift
function but if you're aware of some high-level magic you can:
λ: :set -fprint-explicit-foralls
λ: :t lift
lift
:: forall {t :: (* -> *) -> * -> *} {a} {m :: * -> *}.
(Monad m, MonadTrans t) =>
m a -> t m a
And then you should use @_
to skip some types:
λ: :t lift @MaybeT
lift @MaybeT
:: forall {a} {m :: * -> *}. Monad m => m a -> MaybeT m a
λ: :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, this is really mystery for me why m
is shown as third argument in forall
but should be passed as second but I'm still not aware of all magic.
This is just a hack, but you could always do something like:
:t ap . (id :: ((->) r a) -> ((->) r a))
or
:t \x y -> (id :: ...) (ap x y)
interestingly
Prelude Control.Monad> type Reader = (->) r
Prelude Control.Monad> :t ap . (id :: Reader r a -> Reader r a)
ap . (id :: Reader r a -> Reader r a)
:: Reader r (a -> b) -> (r -> a) -> r -> b
differs from
Prelude Control.Monad> :t \x y -> (id :: Reader r a -> Reader r a) (ap x y)
\x y -> (id :: Reader r a -> Reader r a) (ap x y)
:: (r -> a1 -> a) -> (r -> a1) -> Reader r a
in what ghc recognizes as the synonym Reader r a
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With