Syntactic constructs
Indentation¶
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):
-- treating a prefix function as an infix function
> let subtract x y = x - y
> subtract 6 4
2
> 6 `subtract` 4
2
Functions whose names are symbols, like +, $ and ., 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 + or / that are written by default infix, Haskell has some syntactic sugar to convert functions from infix to  prefix (before their arguments):
-- treating an infix function as a prefix function
> 5 / 2
2.5
> (/) 5 2 -- (1)!
2.5
> (/) 2 5
0.4
> (/ 5)  2 -- (2)!
0.4
> (5 /)  2
2.5
- Whether infix or not, the type of (/)isDouble -> (Double -> Double).
- This is called a "section".
Infixing in types¶
Similarly, -> 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:
> :kind (->)
(->) :: * -> (* -> *)
> :kind (->) Bool
(->) Bool :: * -> *
> :kind (->) Bool Bool 
(->) Bool Bool :: *
Bracketing¶
Haskell tends to avoid brackets when possible.
Expressions like 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
The -> type is right-associative:
- A -> B -> C -> Dmeans- A -> (B -> (C -> D))
Dollar Sign¶
Code like the following is common in Haskell:
This is equivalent to:
Note
$ 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:
Tip
Whenever you see a $, read everything to the right as the input to what is on the left.
Case-of¶
Here is an example of a case _ of statement:
{-# LANGUAGE OverloadedStrings #-}
import Data.Text (Text)
data Color = Black | White
data Piece = Bishop Color | Knight Color | King Color
pieceToText :: ChessPiece -> Text
pieceToText (Piece _ color) = case color of 
    Black -> "black"
    White -> "white"   
This is a convenient way to pattern match.
Guards¶
These are similar to case statements, but instead of pattern matching, you give a boolean condition:
Note
otherwise is not a keyword, in fact it is just the value True:
For this reason, otherwise will always satisfy the guard, and so is an appropriate catch-all final line.
Let-in¶
Let-bindings may be recursive.
Hint
This gives an infinite list. You can sample from it as follows:
See the section on laziness for more information.
Where¶
Similar to let:
See here for differences .
Do-notation¶
Do-notation is a syntax for imperative style programming. It can be used in conjunction with the IO type:
example :: IO ()
example = do
  userInput <- getLine
  let reversed = reverse userInput
  writeFile "file/path" reversed
  print reversed
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.
Note
Do-notation gets converted in the following way:
```haskell
do x <- m f x ```
```haskell
m >>= (\x -> f x) ```
Or for the above example:
```haskell
example :: IO () example = do userInput <- getLine let reversed = reverse userInput writeFile "file/path" reversed print reversed ```
```haskell
example :: IO () example = getLine >>= (\userInput -> let reversed = reverse userInput in (writeFile "file/path" reversed >>= (_ -> print reversed))) ```
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 Monad instances.
Created: January 8, 2023