# Notes from Learning Haskell

## 2018-07-17

It *feels like* there are so many great functions available from Haskell and they seem to make a great deal of sense

Like `succ 1`

gives `2`

, the successor to `1`

I'm used to a method like this being called `add`

, but that *feels* like a function which would mutate and `succ`

does not

Composability feels great

Reading about `max`

(it makes sense that there's a max function, but I hadn't needed it yet), I wondered if I could adapt it for finding the largest value from a list of numbers

And it went exactly as I'd hoped and thought it might!

Where `max 1 2`

gives `2`

, `foldr max 0 [1,2,10,3,4]`

gives `10`

There's likely a better way to do this (and this example returns `0`

if no larger number is found and that's not great), but it's nice that such a thing is so simple

Composing functions is fun

`add x y = x + y`

is the same as `add = (+)`

They both take two arguments and return their sum

Except they aren't the same because the former is a function and the latter is a definition

```
one = 1
add one one
// 2
```

I'm not yet sure how this compares to variables in other languages, but I have some hunches

Trailing apostrophes in function names is a convention to denote strictness (non-laziness) or a slightly modified version of the non apostrophe'd name

I don't know what strictness looks like yet

Lists (`[1,2,3]`

) are homogenous data structures (no mixing types)

`++`

is used for concatenation

`[1] ++ [2]`

gives `[1,2]`

And strings are just lists of characters so

`"Hello," ++ " " ++ "World!"`

gives `Hello, World!`

`foldr (++) [] ["Hello,", " ", "World!"]`

also works (I'm going to keep coming back to `foldr`

, aren't I)

`++`

walks through the entire first list before appending. Yikes

`:`

, known as the cons operator, adds a thing to the beginning of a list and is apparently much more efficient

`1:2:3:[] == [1,2,3]`

`foldr (:) "" ['o', 'k', 'a', 'y'] == "okay"`

Getting an element at an index is accomplished with `!!`

`['o','k','a','y'] !! 0 == 'o'`

Alright I'm kind of shook here...

`head' = (!! 0)`

works? You can pass arguments in upfront? Dang

## 2018-07-24

Using comparators on lists is interesting

```
[1, 1] > [1] -- because 1 and 1 are the same and then 1 is greater than nothing
[1, 3] > [1, 2] -- because 1 and 1 are the same and then 3 is greater than 2
[0] > [] -- because 0 is greater than nothing
```

And there are many functions for working with lists

```
head [0, 1, 2, 3, 4]
-- 0
tail [0, 1, 2, 3, 4]
-- [1, 2, 3, 4]
init [0, 1, 2, 3, 4]
-- [0, 1, 2, 3]
last [0, 1, 2, 3, 4]
-- 4
head []
-- Exception
```

```
length [0, 1, 2, 3, 4]
-- 5
```

```
null []
-- True
null [1]
-- False
```

```
reverse [0, 1, 2, 3, 4]
-- [4, 3, 2, 1, 0]
```

```
take 2 [0, 1, 2, 3, 4]
-- [0, 1]
take 0 [0, 1, 2, 3, 4]
-- []
take 10 [0, 1, 2, 3, 4]
-- [0, 1, 2, 3, 4]
drop 2 [0, 1, 2, 3, 4]
-- [2, 3, 4]
drop 0 [0, 1, 2, 3, 4]
-- [0, 1, 2, 3, 4]
drop 10 [0, 1, 2, 3, 4]
-- []
```

```
maximum [0, 1, 2, 3, 4]
-- 4
minimum [0, 1, 2, 3, 4]
-- 0
```

```
sum [0, 1, 2, 3, 4]
-- 10
product [0, 1, 2, 3, 4]
-- 0
```

```
0 `elem` [0, 1, 2, 3, 4]
-- True
5 `elem` [0, 1, 2, 3, 4]
-- False
```

Ranges seem very friendly

```
[0..4]
-- [0, 1, 2, 3, 4]
['a'..'e']
-- "abcde"
['F'..'J']
-- "FGHIJ"
```

```
[0, 3..9]
-- [0, 3, 6, 9]
['A', 'C'.. 'Z']
-- "ACEGIKMOQSUWY"
```

Different ways to get the first ten multiples of 3

```
[3, 6..3*10] == take 10 [3,6..]
-- True
```

And there are methods for generating lists...

```
take 5 (cycle "LO")
-- "LOLOL"
take 5 (repeat 'A') -- repeat 'A' creates an infinite list
-- "AAAAA"
replicate 5 'A' -- replicate 5 'A' creates a list of five As
-- "AAAAA"
```

## 2018-07-31

List comprehensions are amazing and I don't appreciate having had to live without them for so long

```
[x*2 | x <- [1..3]]
-- [2,4,6]
```

Here's an example with a predicate which filters out even numbers

```
[x | x <- [1..10], odd x]
```

You can also draw from multiple lists getting every possible combination consisting of one value from each list

```
let nouns = ["coffee", "notebook", "headphones"]
let adjectives = ["iced", "fresh", "loud"]
[a ++ " " ++ n | a <- adjectives, n <- nouns]
-- ["iced coffee","iced notebook","iced headphones","fresh coffee","fresh notebook","fresh headphones","loud coffee","loud notebook","loud headphones"]
```

And values from a list fed into a list comprehension don't need to be used

In this example, `length'`

takes a list and converts each of its members to `1`

and then adds them together producing the length of the list

```
length' xs = sum [1 | _ <- xs]
```

Nested list comprehensions are a thing too!

```
let xxs = [[1..3], [4..6], [7..9]]
[ [ x | x <- xs, even x ] | xs <- xxs]
-- [[2],[4,6],[8]]
```

Tuples are fixed size and used for storing heterogenous elements as a single value

```
(1, 'A')
```

A tuple of size two is called a pair and a tuple of size three is called a triple

Tuples of a type must be consistent

```
-- This won't work because the first value in the first pair is a list of characters while the first value in the second pair is a list of numbers
[("foo", 1), ([1,2,3], 2)]
```

There are some handy functions for working specifically with pairs like `fst`

and `snd`

```
fst (1,'A') -- 1
snd (1,'A') -- 'A'
```

`zip`

takes one item at a time from two lists to create tuples until one of the lists is exhausted

```
zip [1..10] [1..]
-- [(1,1),(2,2),(3,3),(4,4),(5,5),(6,6),(7,7),(8,8),(9,9),(10,10)]
```

I'm taking this next exercise on finding right triangles verbatim from Learn You a Haskell

```
-- First we're generating all the triples with integers less than or equal to i
-- 10
[ (a,b,c) | c <- [1..10], a <- [1..10], b <- [1..10]]
-- Then we're adding a predicate to check if the triangles are right triangles
-- by checking that `a^2 + b^2 == c^2`
-- We're also only checking triples where a is less than c because the
-- hypotenuse of a right triangle is always its longest side and we're only
-- checking triples where b is less than a because otherwise we'd end up with
-- duplicated triples
[ (a,b,c) | c <- [1..10], a <- [1..c], b <- [1..a], a^2 + b^2 == c^2]
-- Finally we're adding another predicate to ensure that the sum of the length
-- of the sides is 24 (this is an arbitrary constraint)
[ (a,b,c) | c <- [1..10], a <- [1..c], b <- [1..a], a^2 + b^2 == c^2, a+b+c == 24]
```

## 2018-08-07

In Haskell, every expression's type is known at compile time

Unlike some other languages, Haskell has type inference, so it knows a number is a number without being told it's a number

`:t`

follow by an expression, like `:t ('A', 1)`

, provides the type of that expression

I've been using it a lot as I learn and it's great but also confusing when it says a thing I do understand is a type I don't understand making me suspect that I don't truly understand the thing at all

`::`

is used to describe what type a thing has in code

```
addThree :: Int -> Int -> Int -> Int
addThree x y z = x + y + z
```

`Int`

is an integer with bounds
`Integer`

is an integer without bounds, so it can be used for larger numbers, but it's less efficient than `Int`

`Float`

is a floating-point number with single precision
`Double`

is a floating-point number with double precision (more precise, less performant)

`Bool`

is `True`

or `False`

`Char`

is a unicode character

Tuples have theoretically infinite type possibilities

Haskell supports polymorphic functions which use type variables such as the built-in `head`

```
:t head
head :: [a] -> a
```

Haskell has Type Classes like `Eq`

, which means the thing can be called with `==`

and `/=`

, and `Show`

, which means the thing can be called with `show`

`show`

converts a thing to a string, `read`

, implemented on members of the `Read`

class, converts a string into a thing

```
show 1
-- "1"
read "1" + 1
-- 2
```

## 2018-08-14

When using `read`

to convert a string into another type, type annotations are helpful

```
read "1.0" -- *** Exception: Prelude.read: no parse
read "1.0" :: Float -- 1.0
read "('A', 0)" :: (Char, Int) -- ('A',0)
```

`()`

, `Bool`

, `Char`

, `Ordering`

, `Int`

, `Integer`

, `Float`

, and `Double`

are all members of the `Enum`

type class

This means that they are all enumerable, so each instance can be called with `succ`

and `pred`

and they can all compose ranges

The `Bounded`

type class have an upper and lower bound

```
maxBound :: Int -- 9223372036854775807
```

Tuples whose components are all instances of `Bounded`

are also considered instances of `Bounded`

```
maxBound :: (Int, Char) -- (9223372036854775807,'\\1114111')
```

Instances of `Num`

act like numbers and are all also members of `Show`

and `Eq`

Whole numbers are polymorphic constants

```
:t 100 -- 100 :: Num p => p
-- so
100 :: Float -- 100.0
-- and
(100 :: Double) * (100 :: Double) -- 10000.0
-- because
:t (*) -- (*) :: Num a => a -> a -> a
```

The `Floating`

class includes `Float`

and `Double`

`sin`

, `cos`

, and `sqrt`

require instances of `Floating`

The `Integral`

class includes `Int`

and `Integer`

Integral numbers are whole numbers

`fromIntegral`

converts `Integral`

s into `Floating`

s

```
(read "1" :: Int) + 2.5 -- 3.5
```

## 2018-08-21

Pattern matching is great, definitely cuts down on if/else branching

```
one :: Int -> String
one 1 = "Yay!"
one _ = "Oh no"
one 1 -- Yay!
one 0 -- Oh no
```

Patterns are matched in order, so a catchall should always come last

If there is no catchall, function calls can error, so probably just include a catchall

Tuple pattern matching works like destructuring so

```
wrap :: (String, String) -> String -> String
wrap (x, z) y = x ++ y ++ z
wrap ("(", ")") "hey" -- "(hey)"
```

This works on various sizes of tuples

The `(x:_)`

or `(x:xs)`

syntax is very helpful for recursing with a list and also simple things like `head`

```
head' (x:_) = x
head' "YO" -- Y
head2 (x:y:_) = [x,y]
head2 [1,2,3] -- [1,2]
```

As-patterns are cool -- you get your destructured elements as well as a reference to the original argument

```
firstLetter :: String -> String
firstLetter [email protected](x:_) = "The first letter of " ++ xs ++ " is " ++ [x]
firstLetter "trebuchet" -- The first letter of trebuchet is t
```

Guards are neat -- they're like a compromise between pattern matching and if/else

```
one :: Int -> String
one x
| x == 1 = "Yay!"
| otherwise = "Oh no"
```

They work on boolean expressions, can handle multiple arguments

`where`

is used to store values so they aren't re-calculated unnecessarily

```
sumIs :: [Int] -> String
sumIs xs
| s < 0 = "Less than zero!"
| s `mod` 2 == 0 = "Even!"
| otherwise = "Odd!"
where s = sum xs
sumIs [1,2] -- Odd!
sumIs [1,2,3] -- Even!
sumIs [-10] -- Less than zero!
```

Multiple `where`

values can be provided in the same block

## 2018-08-28

`let`

/`in`

expressions are similar to `where`

but don't span across guards

```
quadruple :: Int -> Int
quadruple x = let double = x * 2 in double * 2
```

They're also usable in more places, like pretty much anywhere

```
squaresOver50 :: [Int] -> [Int]
squaresOver50 xs = [ sq | x <- xs, let sq = x * x, sq > 50 ]
squaresOver50 [1..10] -- [64,81,100]
```

## 2018-09-06

Case expressions are fun

```
one :: Int -> String
one x = case x of 1 -> "Yay!"
_ -> "Oh no"
one 1 -- Yay!
one 0 -- Oh no
```

```
repeat' x = x:repeat' x
take 10 (repeat' 'A') -- AAAAAAAAAA
```

Recursion works how you would expect in a lazy environment