Hello, World!
-------------
Our first example may possibly be familiar: it's called
`helloworld.hs`_.
.. _helloworld.hs: http://static.tobold.org/doio/helloworld.hs
.. include:: helloworld.hs
:literal:
This is about as straightforward as it gets, but there is a lot to
glean here. As promised, we will focus our attention on the types
involved.
This example introduces the function ``putStr``, which has type
``putStr :: String -> IO ()``. In words, ``putStr`` is a function
which takes one argument of type ``String`` and returns a result of
type ``IO ()``. So, when we apply ``putStr`` to an argument, ``putStr
s``, where ``s :: String``, the complete expression has type ``IO
()``.
We will define an *IO action* to be any expression of type ``IO ()``.
By this definition, ``putStr s`` is an IO action. When ``putStr s`` is
*evaluated*, it writes ``s`` to standard output.
Now, we've happily been talking about expressions of type ``IO ()``,
but that's a pretty strange looking type. Let's examine it in detail.
First of all, ``IO`` is a *type constructor*. This means that for *a*\ny
type *a*, there is a related type ``IO`` *a*. You already know about
type constructors, even if you've done very little Haskell, since ``[]``
is a type constructor allowing us to define a list type for any existing
type, such as ``[Int]``, a list of ``Int``\s. If you've done just a
little bit more Haskell, you've probably come across type constructors
such as ``Maybe`` *a*, which allows us to define the type of an optional
value of any other type, for example ``Maybe String``. The ``IO`` type
constructor is very similar to ``Maybe``. (There is an important
difference: ``IO`` is abstract, which means there are no data
constructors corresponding to the ``Just`` and ``Nothing`` constructors
for ``Maybe`` types. This means that you can't simply write down a value
of an ``IO`` type, nor can you pull it apart with pattern matching.)
We will soon be seeing types like ``IO String``, but what is ``IO
()``? You may not have come across ``()`` before, but it is indeed a
type, in fact the *trivial type*. There is only one value of type
``()``, which is also written ``()``: you can think of it as a tuple
with no components. The trivial type is fairly useless on its own, but
``IO ()`` perfectly expresses the type of an IO action that returns no
result, just like ``putStr``.
Just to complete our discussion of types: the type of ``main`` is, the
Haskell report tells us, ``IO`` *a* for some type *a*. In this case,
we have instantiated *a* as the trivial type ``()``, and the entire
program is type correct.
Of course, we can define our own functions with an ``IO ()`` result
type, as in `hellofred.hs`_.
.. _hellofred.hs: http://static.tobold.org/doio/hellofred.hs
.. include:: hellofred.hs
:literal:
This example introduces the function ``putStrLn :: String -> IO
()``. When ``putStrLn`` is evaluated, it writes its ``String``
argument to standard output, followed by a newline character.
The type of ``hello`` is ``hello :: String -> IO ()``, the same as
``putStrLn`` itself.
Exercises
~~~~~~~~~
1. Define ``myPutStrLn`` (identical to ``putStrLn``) in terms of
``putStr``. Solution: `myputstrln0.hs`_.
2. Given ``main = birthday "Fred" 37``, write the function
``birthday`` that will output the line ``Happy Birthday Fred, 37 years
old today!``. What is the type of ``birthday``? Solution:
`birthday.hs`_.
.. _myputstrln0.hs: http://static.tobold.org/doio/myputstrln0.hs
.. _birthday.hs: http://static.tobold.org/doio/birthday.hs