****************************
Chapter 2: Hello, Haskell!
****************************
2.1 Hello, Haskell
------------------
In order to run our code, we'll need a compiler.
Install stack by following the directions on their `website
`_.
.. topic:: Per-user install of stack, the quick version
::
$ wget http://get.haskellstack.org/linux-x86_64.tar.gz &&
tar -xf linux-x86_64.tar.gz '*/stack' -C ~/.local/bin &&
printf '%s\n' 'PATH=$HOME/.local/bin:$PATH' >> ~/.profile
This snippet makes assumptions based on my environment,
and may not make sense for you, so consider the trade-offs.
I've also omitted directions on verifying the binary and making
sure ``$PATH`` is sane.
.. topic:: The difference between stack and cabal
Here is a short summary of the difference between stack and cabal:
https://gist.github.com/merijn/8152d561fb8b011f9313c48d876ceb07
Stack manages the entire tool-chain that you'll typically use for a
project in an isolated way. Right now we're only interested in it
because it will provide a compiler to execute our code with.
.. topic:: Setting up a knowledge base
If you're like me, at this point you probably want to set up a small
knowledge base of resources to learn haskell. Here are some relevant
links:
* `Codeslowers Haskell cheat sheet (pdf) `_
* `Haskell in one video, a video cheat sheet `_
* `A survey and orientation guide of the Haskell landscape (tooling,
libraries, best practices, some basic language features) `_
* `An excellent video series `_
* `The GHC users guide `_
* `The Haskell 2010 language report `_
* `A hierarchial list of libraries included with a typical installation of haskell
`_
I've included a bash script to download these things for you, in pdf
where possible, under ``02_-_hello_haskell/fetch_resources.bash``.
Some other resources:
* `Hoogle `_ is like a search engine
for API docs. You'll want to bookmark this.
* A directory of frequently used modules, included with GHC:
http://downloads.haskell.org/~ghc/8.6.5/docs/html/libraries/index.html
* The freenode IRC #haskell channel is incredibly helpful, too.
2.2 Interacting with Haskell code
---------------------------------
Although Haskell is an ahead-of-time compiled language, it provides
both a compiler and an interpreter.
The compiler is known as GHC, short for Glasgow Haskell Compiler. You
can read more on the `homepage `_ or
peruse its `documentation `_. The interpreter, GHCi, is also part of the
GHC project.
When working with a compiler, the steps to run your code go roughly
like this:
* Edit and save your source code into a file,
* compile that file by running ``stack ghc $file`` as a separate step,
* and run the compiled artifact it produced from your shell like ``./progname``.
(This is of course the most naive possible workflow; it can be more automated.)
Working with an interpreter goes more like this:
* Start the interpreter with ``stack ghci``;
* type code into it and watch it be executed immediately.
Now try bringing up your prompt with ``stack ghci`` and entering some
arithmetic, to see if it's working.
::
Prelude> 2 + 2
4
Prelude> 7 < 9
True
Prelude> 10 ^ 2
100
As an elaboration of the workflow above, ghci allows you to load
existing files into your interactive session. To do so, type ``:load
$filename`` inside the repl.
You can also load a module, like ``:load module`` and GHC will search
for it in its search path. ``:load *module`` will not only load the
declarations the module exports, but also things internal to it.
Special commands that only GHCi understands start with the ``:``
character. Here are a few useful ones::
$ stack ghci
:load filename
:reload
:{
multi-line
expression
:}
-- evaluation order matters in the repl
let x = 4 -- "let" is needed to declare regular variables in older versions of GHCi
let x = 10 -- unlike in source files, you can reassign the same name to different values
-- newer versions of GHCi don't need the "let"
:info
:type
:doc -- only available in newer version of ghci
:browse
:show bindings
:quit
For more, check the GHC documentation.
2.2.2 What is Prelude?
^^^^^^^^^^^^^^^^^^^^^^
Prelude is the standard module. It is imported into all Haskell files
by default, unless there is an explicit import declaration hiding it,
or the ``NoImplicitPrelude`` compiler extension is enabled, like
``stack ghci -XNoImplicitPrelude``.
Prelude is part of the ``base`` package, which comes with GHC. The
``base`` package includes other modules, too. You can read more `here
`_.
Here is a function with a type signature for your inspection::
sayHello :: String -> IO ()
sayHello x = putStrLn ("Hello, " ++ x ++ "!")
The double colon, ``::``, is read as "has the type". The entire line
would be read as "sayHello has the type String to IO unit". (Unit is
how you pronounce the empty tuple, ``()``.)
2.3 Understanding expressions
-----------------------------
Everything in Haskell is an expression or declaration.
Expressions are the building blocks of our programs, and programs
themselves are one big expression made of smaller expressions.
Declarations are top-level bindings which allow us to name
expressions.
2.3.1 Normal form
^^^^^^^^^^^^^^^^^
We say that expressions are in *normal form* when there are no more
evaluation steps that can be taken, or put differently, when they've
reached an irreducible form. Reducible expressions are also called
*redexes*.
2.4 Functions
-------------
A function is an expression that is applied to an argument and always
returns a result.
As in the lambda calculus, all functions in Haskell take one argument
and return one result. When it seems like we're passing multiple
arguments to a function, we are actually applying a series of nested
functions, each to one argument. This is called currying.
Functions are how we factor out patterns common to expressions into
something we can reuse with different inputs.
Here's one example of a simple function definition::
-- name body
-- v vvvvv
triple x = x * 3
-- ^
-- parameter
2.4.2 Capitalization matters!
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Unlike Ada, Nim, and windows batch, identifiers are case sensitive.
``camelCase`` is the current convention for variables and functions.
``PascalCase`` is used for type constructors, data constructors, and
type class names, things you'll learn about later. This is enforced by
the compiler.
You can also use underscores and single quotes in identifiers.
Adding a single quote after a variable name sometimes suggests a
slightly altered version of it. In that circumstance, a single quote
is read as "prime".
Adding a ``_`` after the name may suggest that the output is thrown
out. There are a few loose conventions like this, you'll learn them
over time.
2.5 Evaluation
--------------
Evaluation is program execution. Haskell uses a non-strict evaluation strategy,
which defers evaluation of terms until they're forced by other terms requiring
them. Simplifying a term is called reducing. Values are a terminal point of
reduction.
Haskell doesn't evaluate everything to normal form by default. Instead
it only evaluates to weak head normal form.
Here's a great video on it `Haskell for Imperative Programmers #31 - Weak Head
Normal Form`_.
.. _Haskell for Imperative Programmers #31 - Weak Head Normal Form:
https://www.youtube.com/
watch?v=QBQ9_9R7o8I&list=PLe7Ei6viL6jGp1Rfu0dil1JH1SHk9bgDV
&index=32&t=0s
.. TODO Exercises: Comprehension Check -- page 35
2.6 Infix operators
-------------------
Functions default to prefix syntax, but you can also create infix
functions, which are known as operators.
Here's an example::
·∾ x |> f = f x
·∾ 3 |> (+ 12)
15
If the function name is alphanumeric, it is a prefix function by
default. If the name is a symbol, it is prefix by default.
You can also use prefix functions as infix by surrounding them with
backticks::
·∾ 10 `div` 4
2
·∾ div 10 4
2
...and you can use infix functions a prefix by surrounding them with
parenthesis::
·∾ (+) 3 4
7
2.6.1 Associativity and precedence
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
You can query the fixity, associativity, and precedence of a function
using ``:info``::
·∾ :info (+)
class Num a where
(+) :: a -> a -> a
-- v-- precedence out of the range 0..9, where 9 binds most tightly
infixl 6 +
-- ^-- the l means left associative
.. topic:: The detils of associativity, precedence, and fixity
Associativity is how arguments group to functions during a step
in the evaluation process. If something is left associative,
arguments to the left of an infix function are consumed first. If
something is right associative, arguments to the right of the
infix function are consumed first. Haskell additionally has
non-associative operators, like ``==``, ``/=``, ``<``, ``<=``,
``>``, ``>=``, ``\`elem\```, and ``\`notElem\```.
Here's two examples where each term in the overall expression has the
same associativity:
Left associative, ``f 1 2 3`` ≡ ``(((f 1) 2) 3)``.
Right associative, ``1 2 3 f`` ≡ ``(1 (2 (3 f)))``.
Precedence determines which function is evaluated first (who gets
first turn at consuming arguments). In Haskell precedence goes
from 0-9, where 9 is the highest (evaluated first). In Haskell,
functions get a precedence of 9 by default (``infixl 9``).
Additionally function application behaves as if it has fixity 10,
record updates behave as if they have fixity 11.
I asked about the default precedence of prefix function
definitions on IRC, and learned some things not in the 2010
Language Report.
| **geekosaur** the default fixity of a function is infixl 9.
|
| **ski** justsomeguy: fixity of function application
| (juxtaposition syntactic operator) is 10.
|
| **geekosaur** Function application behaves as if it has fixity
| 10, record updates behave as if they had fixity 11.
|
| **justsomeguy** ski: I thought that precedence only goes from
| 0..9? Or maybe that's only the range for fixity declarations,
| rather than fixity in general?
|
| **ski** Ordinary (definable) operators have precedences
| from zero to nine, sure.
|
| **justsomeguy** Thank you, that clears things up. I wish the
| language report made that a little more obvious.
|
| **monochrom** Function application and record syntax cannot
| be formally given predence levels because there is no
| binary operator to attach the predence levels to.
|
| And the Haskell Report is supposed to give formal
| definitions not intuitive conceptual moral fast-and-loose
| bedtime stories.
|
| So it has to hide the intuitive interpretation in a
| formal grammar.
|
| [Ed: The function application operator is technically not
| an operator, but a component of the AST.]
You can have expressions that contain many functions with different
associativity and different precedence. For example::
-- (^) is right associative
8 + 3 ^ 12 * 3
-- Explicitly parenthesised, ()s show
-- associativity, {}s show precedence.
--
(8 +) {({3 (^ 12)} *) 3 }
-- ^ ^ ^
-- left right left
Fixity is where functions or operators are placed in relation to the
arguments they consume. Some examples of fixity are infix, prefix,
postfix, `circumfix, precircumfix, and postcircumfix `_,
or even `mixfix `_. In haskell there are two possible
fixities: prefix or infix. Language extensions may enable you to
have more, I don't know.
Arity is the number of arguments that a function consumes. A binary
function takes two arguments. A ternary function takes three. A
finitary function takes a finite number of arguments. An infinitary
function takes an infinite number of arguments. A nullary function
takes no arguments. You get the idea.
.. include:: exercises/2.6.2_-_parentheses_and_association.rst
2.7 Declaring values
--------------------
The order of declaration in a source code file doesn't matter because
GHCi loads the entire file at once, so it known all the values that
have been defined.
On the other hand, when you enter them one by one into the repl, the
order does matter.
Module names must begin with an uppercase letter.
2.7.1 Troubleshooting
^^^^^^^^^^^^^^^^^^^^^
White-space is significant in Haskell, just like Python.
The basic rule is that subsequent lines belonging to an expression
should be written under the beginning of that expression at the same
level of indentation.
+---------------+---------------+
| Correct | Incorrect |
+===============+===============+
| :: | :: |
| | |
| let | let x = 3 |
| x = 3 | y = 4 |
| y = 4 | |
| | -- or |
| -- or | |
| | let |
| let x = 3 | x = 3 |
| y = 4 | y = 4 |
| | |
+---------------+---------------+
You can read about the particulars in the 2010 language report,
section 2.7 Layout.
.. include:: exercises/2.7.2_-_heal_the_sick.rst
2.8 Arithmetic functions in Haskell
-----------------------------------
.. include:: figures/arithmetic_functions.rst
The ``mod`` and ``rem`` functions keep on tripping me up.
https://ebzzry.io/en/haskell-division/
.. .. include:: figures/arithmetic_ghci_examples.rst
2.8.1 Laws for quotients and remainders
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. include:: figures/laws_for_quotients_and_remainders.rst
2.8.2 Using mod
^^^^^^^^^^^^^^^
If you're unfamiliar with modular division, you may not understand the
useful difference between mod and rem.
Modular arithmetic is a system of arithmetic for integers where
numbers "wrap around" upon reaching a certain value, called the
*modulus* (the second argument to ``mod``).
2.8.3 Negative numbers
^^^^^^^^^^^^^^^^^^^^^^
Negative numbers need to be surrounded in parenthesis, like this
``(-9)``. Otherwise the compiler may confuse the negative sign with
the infix subtraction operator. When ``-`` is used infix, it's a
synonym for ``subtract``.
Using ``-`` to make a number negative is syntactic sugar; You can
instead write it like this ``(negate 9)``. This is a bit of a special
case.
2.9 Parenthesization
--------------------
If you want to inspect an infix operator with ghci using the ``:info``
command, you usually have to surround it with parenthesis, like
``:info (^)``, for example.
The ``$`` operator can be used to avoid parenthesis, sometimes. It
will allow everything to the right of it to be evaluated first and can
be used to delay function application.
::
·∾ (2^) $ (+2) $ 3 * 2
256
2.9.1 Parenthesizing infix operators
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
You can also use parenthesis to apply only some arguments to a
function, and leave the other parameters available for binding.
Applying only some arguments is known as *partial application*.
For example ``(2^)`` is equivalent to ``(^) 2``, or more verbosely
``\x -> 2 ^ x``.
When you do this by surrounding the function with parenthesis, this is
sometimes known as *sectioning*.
Subtraction is a special case; ``(-2) 1`` won't work, because ``-`` has a
special case that it's treated as ``negate`` within parenthesis and
prefacing a numeric literal. ``(subtract 2) 1`` will give the desired
effect.
When sectioning operators, pay special attention to the associativity,
it will change the result.
2.10 Let and where
------------------
``let`` introduces an expression, so it can be used wherever you can
have an expression, but ``where`` is a declaration, and is bound to
the surrounding syntactic construct.
.. include:: exercises/2.10.1_-_exercises_a_head_code.rst
2.11 Chapter Exercises
----------------------
.. include:: exercises/2.11.1_-_parenthesization.rst
.. include:: exercises/2.11.2_-_equivalent_expressions.rst
.. include:: exercises/2.11.3_-_more_fun_with_functions.rst