# Syntactic constructs

## Indentation¶

Haskell is indentation sensitive, like Python. Tabs or spaces are fine.

example input = result <> " tree" where
result = case input of
True -> "red"
False -> "black"


## Infixing and sections¶

Given a function f, one can write it infix (i.e. in between its two arguments):

repl example
-- 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): repl example -- 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  1. Whether infix or not, the type of (/) is Double -> (Double -> Double). 2. 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: repl example > :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 z means ((f x) y) z • Either Bool Int means (Either Bool) Int The -> type is right-associative: • A -> B -> C -> D means A -> (B -> (C -> D)) ### Dollar Sign¶ Code like the following is common in Haskell: exampleWithDollar = not$ (> 3) 4


This is equivalent to:

exampleWithoutDollar = not ( (> 3) 4)


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:

exampleWithDollar = not $(> 3)$ head [1,2,3]


means the same as:

exampleWithoutDollar = not ((> 3) (head [1, 2, 3]))


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:

example :: Int -> Bool
example x
| x > 0 && x < 10 = True
| otherwise = False


Note

otherwise is not a keyword, in fact it is just the value True:

repl example
> otherwise
True
> :t otherwise
otherwise :: Bool


For this reason, otherwise will always satisfy the guard, and so is an appropriate catch-all final line.

## Let-in¶

example :: Int
example =
let val1 = 5
val2 = val1 + 5
in val1 + val2 + 1


Let-bindings may be recursive.

example :: Int
example =
let val1 = 0 : val2
val2 = 1 : val1
in val1


Hint

This gives an infinite list. You can sample from it as follows:

> take 20 example
[0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1]


## Where¶

Similar to let:

example = val1 where
val1 = 0 : val2
val2 = 1 : val1


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:

do
x <- m
f x

m >>= (\x -> f x)


Or for the above example:

example :: IO ()
example = do
userInput <- getLine
let reversed = reverse userInput
writeFile "file/path" reversed
print reversed

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.