Haskell is indentation sensitive, like Python. Tabs or spaces are fine.
Infixing and sections¶
Given a function
f, one can write it infix (i.e. in between its two arguments):
Functions whose names are symbols, like
., are written infix by default. An order of precedence is defined, to avoid the need for bracketing. For example,
f a . f b means
(f a) . (f b), and similarly,
f a $ f b means
(f a) $ (f b).
For functions like
/ that are written by default infix, Haskell has some syntactic sugar to convert functions from infix to prefix (before their arguments):
- Whether infix or not, the type of
Double -> (Double -> Double).
- This is called a "section".
Infixing in types¶
-> is a type-level infix operation:
a -> b can be written
(->) a b.
As this suggests,
-> is like
Either in that it is a function on types:
Haskell tends to avoid brackets when possible.
4 * 3 + 5 take a default bracketing (given when the operators were defined).
Functions application is left-associative:
f x y zmeans
((f x) y) z
Either Bool Intmeans
(Either Bool) Int
-> type is right-associative:
A -> B -> C -> Dmeans
A -> (B -> (C -> D))
Code like the following is common in Haskell:
This is equivalent to:
$ is just a regular function, used infix, and defined so that
f $ x = f x.
For more explanation, see: https://typeclasses.com/featured/dollar.
Dollars can be stacked:
means the same as:
Whenever you see a
$, read everything to the right as the input to what is on the left.
Here is an example of a
case _ of statement:
This is a convenient way to pattern match.
These are similar to
case statements, but instead of pattern matching, you give a boolean condition:
otherwise is not a keyword, in fact it is just the value
For this reason,
otherwise will always satisfy the guard, and so is an appropriate catch-all final line.
Let-bindings may be recursive.
This gives an infinite list. You can sample from it as follows:
See the section on laziness for more information.
See here for differences .
Do-notation is a syntax for imperative style programming. It can be used in conjunction with the IO type:
Here, the order of operations is top-down (read line, write file, print), and the
<- arrow gives a name to the result of an operation (like
userInput, which is the result of reading from stdIn with
getLine) which can be used later.
Do-notation gets converted in the following way:
Or for the above example:
As this shows, not only
IO, but any type
f :: * -> * which is an instance of
Monad (and thus implements
>>=) can be used with do-notation. For this reason, do-notation is common in Haskell code with many different
Created: January 8, 2023