What is the type of return "abc"
when printed in ghci?
The point of the question is that it's polymorphic in the monad:
ghci> :t return "abc"
return "abc" :: (Monad m) => m [Char]
and what gets printed depends on which monad is chosen:
ghci> return "abc" :: Maybe String
Just "abc"
ghci> return "abc" :: [] String
["abc"]
but here's what's actually printed:
ghci> return "abc"
"abc"
A function that can evaluate to or be applied to values of different types is known as a polymorphic function. A data type that can appear to be of a generalized type (e.g. a list with elements of arbitrary type) is designated polymorphic data type like the generalized type from which such specializations are made.
In Object-Oriented programming languages there are three types of polymorphism: subtype polymorphism, parametric polymorphism, and ad-hoc polymorphism.
Three branches of polymorphism In object-oriented programming, this is often called generic programming. Inclusion polymorphism, also known as subtyping, is when a single name refers to many instances of different classes as long as they share the same superclass.
In programming languages, ad hoc polymorphism is a kind of polymorphism in which polymorphic functions can be applied to arguments of different types, because a polymorphic function can denote a number of distinct and potentially heterogeneous implementations depending on the type of argument(s) to which it is applied.
When you type an expression expr
into GHCi, the following things happen:
expr
is found to have type t
; GHC tries to match t
against IO a
.it <- expr
, then if a
is an instance of Show
and is not ()
, it executes print it
.t
itself is an instance of Show
, GHCi does something like let it = expr
and then print it
.Essentially, you need a way at the GHCi prompt both of running IO actions and getting at the values they return, and of playing around with pure values and seeing what you get. That's why GHCi behaves the way it does: if it seems like you're using an IO action, GHCi will do it, and then if that action has a result that can be shown and is interesting (i.e. not ()
) then it shows the result to you. If it can't show the result to you, then it's no big deal, because you probably just wanted to run the IO action anyway; if you wanted the result you would have named it with <-
. On the other hand, if it seems like your expression is not an IO action, GHCi calculates it and shows it to you, and if it can't be shown then GHCi can't do anything useful (no side-effects this time), so complains.
In this case, return "abc"
typechecks as IO String
, and String
is an instance of Show
, so GHCi does something like
it <- return "abc"
print it
which by the monad laws is exactly the same as just doing
print "abc"
hence the result.
Haskell has a slightly baffling set of rules for deciding the types of expressions involving numbers; you can see the Report section on ambiguous types and default instances. So the answer to the general question is complicated. But within GHCi, if you enter an expression e, you can rely on these rules to apply:
If the expression e can be typed as IO T
for some type T
, and if T
has a Show
instance, GHCi will run the computation and print the resulting value of type T
. That's what's happening in your third example.
If the expression e *cannot* be typed in the IO
monad, then the default-instance rules come into play, and GHCi will choose a type according to those rules. If the type has a Show
instance GHCi will then print show
e. That's what happens in your first two examples: Maybe String
and [String]
are pure values with Show
instances.
If e's type does not have a Show
instance, then GHCi will complain. That will happen if you type an expression like flip take
.
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