Reputation: 831
I don't understand why the following exercise "works" in Haskell Programming from First Principles:
type Subject = String
type Verb = String
type Object = String
data Sentence =
Sentence Subject Verb Object
deriving (Eq, Show)
s1 = Sentence "dogs" "drool"
s2 = Sentence "Julie" "loves" "dogs"
Loading this into ghci shows that it typechecks just fine, but why is it that the definition of s1
even makes sense? I'm still very new to Haskell, so at first I thought this was because in s1
Haskell was implicitly letting the Object
string be empty. But then...
*Main> s1
<interactive>:13:1:
No instance for (Show (Object -> Sentence))
arising from a use of `print'
Possible fix:
add an instance declaration for (Show (Object -> Sentence))
In a stmt of an interactive GHCi command: print it
I'm still learning how to properly interpret these error messages, so please bear with me. But can someone explain what No instance for (Show (Object -> Sentence))
means? More specifically, how does leaving out the Object
string in s1
result in this (Object -> Sentence)
thing?
I'm sure this is stupid easy, but I don't think the book has equipped me to understand this by this point...
Upvotes: 4
Views: 956
Reputation: 7631
No instance for (Show (Object -> Sentence)) arising from a use of `print' Possible fix: add an instance declaration for (Show (Object -> Sentence)) In a stmt of an interactive GHCi command: print it
To supplement @ErikR's answer: you may be wondering why GHC doesn't have a built-in support for displaying functions, i.e. unlike integers and strings, functions don't have an instance for the Show
typeclass (these terms will be explained in depth later in the book, so don't worry if you don't understand what's a typeclass and an instance), unless you explicitly define it yourself. As someone who is learning Haskell and comes from an Object-Oriented background, I found it easier to get an intuition for typeclasses by thinking of them as Java-like interfaces.
So, why there's no Show
insance for functions? The Haskell wiki provides two answers:
1.Practically, GHC doesn't keep track of variable names, i.e. the following are the same for the compiler:
addOne num = num + 1
f x = x + 1
f y = y + 1
Additionally, functions can be optimized, e.g. the following may have equivalent representations
f x = x - x + x
f x = x
2.Theoretically, a function is defined by its graph, i.e. the set of (input, output) pairs. e.g. for
f x = x + x
the pairs are (1,2), (2,4), etc. Thus, functions with the same graph are identical GHC-wise, e.g
f x = x + x
g y = 2 * y
but you would expect show f
and show g
to be different, especially if you use significant variable names instead of x and y.
That said, you can use a pragma (an extension for the GHC compiler, that contains some functionality beyond the Haskell language standard) that would show only the function's type, as explained in this answer:
{-# LANGUAGE ScopedTypeVariables #-}
import Data.Typeable
instance (Typeable a, Typeable b) => Show (a->b) where
show _ = show $ typeOf (undefined :: a -> b)
This will get you
> s1
[Char] -> Sentence
since Object
is an alias of String
(using the type
keyword, String
is itself an alias for [Char]
).
If you want to explicitly see the distinction between subjects and objects, you can convert Object
to a type with a datatype constructor MkObject
:
newtype Object = MkObject String deriving (Eq, Show)
s1 = Sentence "dogs" "drool"
s2 = Sentence "Julie" "loves" (MkObject "dogs")
and voilà
> s1
Object -> Sentence
Upvotes: 0
Reputation: 52039
but why is it that the definition of
s1
even makes sense?
As @Alec mentioned, it's called currying. One way to see what is going on is to have GHCI tell you what the type of s1
is:
ghci> :t s1
s1 :: Object -> Sentence
So s1
is a function taking an Object
to a Sentence
. Another way to think about is to start with the definition:
s1 = Sentence "dogs" "drool"
and using equational reasoning apply both sides to a value x
:
s1 x = Sentence "dogs" "drool" x
So when you call s1 x
it's the same as calling Sentence
with the first two function arguments hard-coded to "dogs"
and "drool"
, and x
becomes the third argument to the Sentence
function.
can someone explain what "No instance for
(Show (Object -> Sentence))
" means?
When you evaluate something in GHCI is it basically the same as asking Haskell to print
it. That is,
ghci> 3+4
is effectively the same as:
ghci> print (3+4)
(This rule doesn't apply to IO-actions like getLine
or even print
itself. In those cases Haskell just runs the IO-action.)
In order to print
something there has to be a Show instance for the type.
But as we've seen above, s1
is a function of type Object -> Sentence
, and there are no predefined Show instances for functions.
Note that there is a Show instance for Sentence
values because you asked GHC to derive one with deriving (Eq, Show)
. So when you type at the GHCI prompt:
ghci> Sentence "Julie" "loves" "dogs"
you get back:
Sentence "Julie" "loves" "dogs"
because you are really asking GHCI to run print (Sentence "Julie" "loves" "dogs")
.
Note that print
itself is defined as (link):
print x = putStrLn (show x)
and the call to show
is the reason why a value needs to have a Show instance defined for it in order to print it.
Upvotes: 8