Migrated
This commit is contained in:
126
Functional Programming/Basic Haskell.md
Normal file
126
Functional Programming/Basic Haskell.md
Normal file
@ -0,0 +1,126 @@
|
||||
---
|
||||
type: mixed
|
||||
---
|
||||
|
||||
## Function definitions
|
||||

|
||||
|
||||
- We don't have a return, we have an expression
|
||||
- Calling a function is done like this:
|
||||
```haskell
|
||||
name arg1 arg2 ... argn
|
||||
```
|
||||
Or in this case:
|
||||
``` haskell
|
||||
add 1 2 -- This will return 3
|
||||
```
|
||||
|
||||
|
||||
## Types
|
||||
```haskell
|
||||
name :: <type>
|
||||
```
|
||||
|
||||
### Integer
|
||||
```haskell
|
||||
x :: Integer
|
||||
x = 1
|
||||
```
|
||||
|
||||
### Boolean
|
||||
```haskell
|
||||
y :: Bool
|
||||
y = True
|
||||
```
|
||||
|
||||
### Float
|
||||
```haskell
|
||||
z :: Float
|
||||
z = 1.6
|
||||
```
|
||||
- Data Types
|
||||
|
||||
- **Int**: platform-dependent precision integers
|
||||
- **Char**: character literals, functions from Data.Char module (e.g., isSpace, isDigit, isAlpha, isLower, isUpper, toLower, toUpper, digitToInt)
|
||||
- **Tuple types**: (e1, ..., en), functions fst and snd for pairs
|
||||
|
||||
- Type classes
|
||||
- `Num`: numeric types (e.g., Int, Integer, Float, Double)
|
||||
- `Eq`: equality types, with operators `==` and `/=`
|
||||
- `Ord`: ordered types, with operators `<` and `<=`
|
||||
|
||||
[More types here](https://www.tutorialspoint.com/haskell/haskell_types_and_type_class.htm)
|
||||
|
||||
## Infix functions
|
||||
|
||||
- Functions written **between** their arguments, rather than before them.
|
||||
- `5 + 3` is an infix function
|
||||
- By default, functions with symbols (like `+`, `-`, `*`) are infix.
|
||||
- You can also make any function infix by surrounding it with backticks (`` ` ``).
|
||||
|
||||
Continuing with the `add` example, we could call it like this:
|
||||
```haskell
|
||||
add 5 3 -- 8
|
||||
```
|
||||
but we could also do this
|
||||
|
||||
```haskell
|
||||
5 `add` 3
|
||||
```
|
||||
|
||||
This achieves more natural placement of the function (in some cases).
|
||||
|
||||
## Types in functions
|
||||
|
||||
We define them as a chain of types for the arguments (including the return type) with `->`
|
||||
In the `add` example:
|
||||
|
||||
```haskell
|
||||
add :: Integer -> Integer -> Integer
|
||||
add x y = x + y
|
||||
```
|
||||
|
||||
|
||||
## Let
|
||||
- Save the result of an expression and then return it
|
||||
- Defines variables **before** the main expression
|
||||
```haskell
|
||||
let <name> = <expression> in <result>
|
||||
```
|
||||
|
||||
i.e.
|
||||
```haskell
|
||||
let x = 5
|
||||
y = 10
|
||||
in x + y -- This will "return" x+y = 15
|
||||
```
|
||||
|
||||
|
||||
## Where
|
||||
- Inverse of let - defines variables **after** the main expression
|
||||
- Makes more intuitive mathematical sense
|
||||
|
||||
```haskell
|
||||
<result> where <name> = <expression>
|
||||
```
|
||||
|
||||
i.e.
|
||||
```haskell
|
||||
x + y where
|
||||
x = 5
|
||||
y = 10
|
||||
```
|
||||
|
||||
|
||||
|
||||
## If branches
|
||||
### If then else (ternary)
|
||||
```haskell
|
||||
equalize x y =
|
||||
if xLarger then x - 1 else y - 1
|
||||
where
|
||||
xLarger = x > y
|
||||
|
||||
```
|
||||
|
||||
|
@ -0,0 +1,23 @@
|
||||
---
|
||||
type: mixed
|
||||
---
|
||||
|
||||
|
||||
## Definition
|
||||
- Pure mathematical functions
|
||||
- Declarative paradigm
|
||||
- Instead of writing step-by-step, we define the desired outcome
|
||||
- Immutable data
|
||||
- => No/Less side effects
|
||||
- Programs are easier to verify
|
||||
- We can mathematically prove the algorithms
|
||||
|
||||
|
||||
## Lazy vs. Strict
|
||||
- Calculations are delayed until the results are actually needed
|
||||
|
||||
### Example
|
||||
Imagine a list of numbers, but you only need the first one that meets a condition. With lazy evaluation, the program stops processing the list as soon as it finds the result, instead of checking every number.
|
||||
|
||||
|
||||
|
36
Functional Programming/Lists.md
Normal file
36
Functional Programming/Lists.md
Normal file
@ -0,0 +1,36 @@
|
||||
---
|
||||
type: mixed
|
||||
---
|
||||
### Stuff
|
||||
- Definition and syntax of lists
|
||||
- List comprehension:
|
||||
- Set comprehensions and list comprehension
|
||||
- Generators (pattern <- list expression)
|
||||
- Tests (Boolean expressions within list comprehension)
|
||||
- Multiple generators and dependent generators
|
||||
- Meaning of list comprehensions
|
||||
- Important list functions:
|
||||
- `length`
|
||||
- `++` (concatenation)
|
||||
- `reverse`
|
||||
- `replicate`
|
||||
- `head`, `last`, `tail`, `init`
|
||||
- `take`, `drop`
|
||||
- `concat`
|
||||
- `zip`, `unzip`
|
||||
- `and`, `or`, `sum`, `product`
|
||||
- Pattern matching on lists:
|
||||
- Constructors: `[]` (empty list) and `:` (cons operator)
|
||||
- Patterns and pattern matching using wildcards (_)
|
||||
- Recursion over lists
|
||||
- Indexing lists using `!!` operator
|
||||
- Examples:
|
||||
- `concat` function using primitive recursion
|
||||
- `insertionSort` function
|
||||
- `zip` and `take` functions using multiple arguments in recursion
|
||||
- `quickSort` function using general recursion
|
||||
- `reverse'` function using an accumulating parameter
|
||||
- `ups` function (finding maximal ascending sublists) using an accumulating parameter
|
||||
|
||||
|
||||
|
10
Functional Programming/Polymorphism.md
Normal file
10
Functional Programming/Polymorphism.md
Normal file
@ -0,0 +1,10 @@
|
||||
---
|
||||
type: mixed
|
||||
---
|
||||
### Stuff
|
||||
|
||||
- Definition of polymorphism and type variables
|
||||
- Examples of polymorphic functions:
|
||||
- `id`, `fst`, `swap`, `silly`, `silly2`
|
||||
- List functions from the Prelude (e.g., `length`, `++`, `reverse`, `replicate`, `head`, `tail`, `take`, `drop`, `concat`, `zip`, `unzip`, `and`, `or`, `sum`, `product`)
|
||||
- Polymorphism vs. overloading
|
96
Functional Programming/Recursion.md
Normal file
96
Functional Programming/Recursion.md
Normal file
@ -0,0 +1,96 @@
|
||||
---
|
||||
type: mixed
|
||||
---
|
||||
|
||||
[Divide and Conquer](Divide%20and%20Conquer.md)
|
||||
## Loops do not exist in Haskell
|
||||
So we have to use recursion!
|
||||
|
||||
```haskell
|
||||
funcName <args> = ... name <args'> ...
|
||||
```
|
||||
|
||||
where `args'` is the augmented args (recursive).
|
||||
|
||||
using if-then-else
|
||||
```haskell
|
||||
factorial :: Int -> Int
|
||||
factorial n =
|
||||
if n == 0 then
|
||||
1
|
||||
else
|
||||
n * factorial(n-1)
|
||||
```
|
||||
|
||||
|
||||
## Guards
|
||||
Moving from the `factorial` example:
|
||||
```haskell
|
||||
factorial n
|
||||
| n == 0 = 1
|
||||
| otherwise = n * factorial (n-1) -- Catch all
|
||||
```
|
||||
|
||||
Note the indentation and the pipes (`|`). We can add any amount of conditions, unlike the if-then else.
|
||||
|
||||
|
||||
## Pattern matching
|
||||
i.e. with the `factorial` example. `_` is a wildcard (ignore the value). Note how we are "re-defining" the function
|
||||
|
||||
```haskell
|
||||
factorial :: Int -> Int
|
||||
factorial 0 = 1 -- Base case: when n is 0
|
||||
factorial n = n * factorial (n - 1) -- Recursive call with n-1
|
||||
|
||||
```
|
||||
|
||||
|
||||
## Accumulators
|
||||
|
||||
A variable that **accumulates** or **stores** a running total or result during the execution of a function, especially in loops or recursive functions. It is essentially a helper function.
|
||||
|
||||
```haskell
|
||||
factorial :: Int -> Int
|
||||
factorial n = factorialHelper n 1
|
||||
where
|
||||
factorialHelper 0 acc = acc -- Base case: when n is 0, return the accumulator
|
||||
factorialHelper n acc = factorialHelper (n - 1) (n * acc) -- Multiply n by accumulator and recurse
|
||||
|
||||
```
|
||||
|
||||
In this example, by using an accumulator and tail-recursion[^1] we achieve a $\mathcal{O}(n)$ time complexity [^2]. We should **always strive for tail-recursive algorithms**, as normal recursion *can* cause stack overflow.
|
||||
|
||||
|
||||
## Function composition
|
||||
|
||||
In Haskell, the **composition operator** is `(.)`. It allows us to compose two functions together into a new function.
|
||||
|
||||
The operator is defined as:
|
||||
```haskell
|
||||
(f . g) x = f (g x)
|
||||
```
|
||||
|
||||
|
||||
i.e. we have 2 functions:
|
||||
|
||||
```haskell
|
||||
increment :: Int -> Int
|
||||
increment x = x + 1
|
||||
|
||||
square :: Int -> Int
|
||||
square x = x * x
|
||||
|
||||
```
|
||||
|
||||
we can combine them like so:
|
||||
```haskell
|
||||
incrementThenSquare :: Int -> Int
|
||||
incrementThenSquare = square . increment
|
||||
```
|
||||
|
||||
|
||||
---
|
||||
|
||||
[^1]In tail recursion, the recursive call is the ***last operation*** in the function. This means that once a recursive call is made, there’s no need to retain the current function’s state or stack frame.
|
||||
|
||||
[^2] Computational limits still exist! Although the time complexity is perceived as $\mathcal{O}(n)$, that may not actually be the case, as computers are slow.
|
BIN
Functional Programming/assets/Pasted image 20241125164049.png
Normal file
BIN
Functional Programming/assets/Pasted image 20241125164049.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 18 KiB |
Reference in New Issue
Block a user