# Introducing the Haskell language

- Tram Ho

**Functional Programming**

First, let’s consider two concepts:

**• Imperative Programming:** Programming commands, we use commands to change the state of the program. We will guide the program to step by step from beginning to end, or repeat certain commands, …

**• Declarative Programming:** Programming declarations, we will tell the program what we want, not how to do it. We do not specify the steps as in order programming.

Functional Programming is a branch in Declarative Programiming, in which, we will take the function as a basic unit (similar in object-oriented programming, the object will be the basic unit). In general, we have the following characteristics:

## 1. Purity

A function called `pure`

if it takes parameters is a value and always returns a value without changing any external state. And with the same input, the function will return a corresponding value.

For example, consider a function in `Swift`

as follows:

1 2 3 | func add (_ a: Int, _ b: Int) -> Int { return a + b } |

This function is `pure`

because it doesn’t change anything outside. However, the following function is not `pure`

because of the same input that returns different values:

1 2 3 | func radd (_ a: Int, _ b: Int) -> Int { return Int.random (in: 0 ... 10) * (a + b) } |

But like that, printing a line of text to the screen also causes a change of state, so how do I use only pure functions? In Functional Programming, we must also have `IO`

operations, which are `impure`

operations, they will be encapsulated into one place to facilitate management. The function of Functional Programming is to minimize the side effects by accessing them, not completely removing them.

## 2. Immutability

There will be no change in a numerical `variable`

in Functional Programming, a value stored in a `variable`

will forever receive that value, generally it is a `const variable`

. You have learned that `Swift`

will definitely be used to a lot of `let`

keywords, there are probably many reasons for this, we see that it minimizes errors when using `const variable`

(and one of the main reasons is that `swiftc`

will roar every time a variable just assigns once, we use `var`

)

## 3. Recursion

In Functional Programming, we do not have keywords like `for, while, repeat, forEach, ...`

To implement loops, we will use recursion. For example:

1 2 3 4 5 6 | int max (int const * const arr, const int n) { if (n == 1) return * arr; int const carry = max (arr + 1, n - 1); if (carry> * arr) return carry; return * arr; } |

A function that finds the largest value in an integer array by recursion must be familiar to many people. Here `int const* const`

indicates that `arr`

must point to a fixed address and the values it points to must be fixed to preserve `immutability`

(the compiler will almost always change something) .

**Haskell**

`Haskell`

is a pure functional programming language (Pure Functional Programming), is a compiled language, and is a static language, but don’t worry too much, the compiler will help us a lot in self-debugging. . `Haskell`

is lazy (Lazy evaluation), unless forced to do it, `Haskell`

will never execute calculations. A simple example has two `repeat`

and `take`

functions as follows:

1 2 3 4 5 6 7 | repeat :: a -> [a] repeat x = x: repeat x take :: Int -> [a] -> [a] take n _ | n <= 0 = [] take _ [] = [] take n (x: xs) = x: take (n-1) xs |

If it is `Python`

, we will write the following:

1 2 3 4 5 | def repeat (x): return [x] + repeat (x) def take (n, seq): if n <= 0 or seq == []: return [] return [x] + take (n-1) seq [1:] |

However, in `Python`

, when we call `take(3, repeat(7))`

, the program will calculate `repeat(7)`

before and after `take`

later. However, when calculating `repeat(7)`

, we will be immediately subjected to a `maximum recursion depth exceeded`

because `repeat(7)`

is an infinite `list`

of `7`

(We can edit the `repeat`

function to make it a `generator`

but here not the main purpose of the article). Now look at `Haskell`

, if anyone doesn’t know, `f x1 x2 ...`

is the implementation of a function `f`

with the parameters `x1, x2, ...`

and `x:xs`

can be interpreted as `x`

as the first element of a `list`

and `xs`

are interpreted as “high probability is the rest” (not the “rest”, only “high probability is the rest”). Now look at `Haskell`

deploying the `take 3 (repeat 7)`

:

1 2 3 4 5 6 7 8 9 | take 3 (repeat 7) = take 3 (7: repeat 7) = 7: take 2 (repeat 7) = 7: take 2 (7: repeat 7) = 7: 7: take 1 (repeat 7) = 7: 7: take 1 (7: repeat 7) = 7: 7: 7: take 0 (repeat 7) = 7: 7: 7: [] = [7, 7, 7] |

With sample `(x:xs)`

in the definition, it will convert `repeat 7`

to `7 : repeat 7`

whenever called. Everything `Haskell`

pure is lazy, but there is still a function that allows us to pre-calculate the parameter value before being executed (and of course it cannot be written entirely in `Haskell`

). `Haskell`

‘s laziness also causes some troubles:

1 2 3 4 5 | lazySum (Num a) => [a] -> a lazySum = go 0 where go curr [] = curr go curr (x: xs) = go (curr + x) xs |

This function takes a list and returns the sum of the elements of that list, with the lazyness of the language, it will do the following:

1 2 3 4 5 6 7 8 9 10 11 | lazySum [1, 2, 3, 4] go 0 [1, 2, 3, 4] go (1 + 0) [2, 3, 4] go (2 + (1 + 0)) [3, 4] go (3 + (2 + (1 + 0))) [4] go (4 + (3 + (2 + (1 + 0))))]] 4 + (3 + (2 + (1 + 0)))) 4 + (3 + (2 + 1)) 4 + (3 + 3) 4 + 6 ten |

Having too many expressions not yet evaluated, `Haskell`

now creates too much `thunk`

. To limit this, as introduced above, there is a function that allows to evaluate a certain value first, `Haskell`

gives us `seq`

:

1 2 | seq ab = b a `seq` b = b |

Where `a`

will be evaluated, or simpler we just need to put `!`

before the variable we need to evaluate before the function runs with the `-XBangPatterns`

command flag. So we will rewrite the above function as follows:

1 2 3 4 5 | betterSum (Num a) => [a] -> a betterSum = go 0 where go curr [] = curr go curr (x: xs) = curr `seq` go (x + curr) xs |

or:

1 2 3 4 5 | betterSum (Num a) => [a] -> a betterSum = go 0 where go curr [] = curr go! curr (x: xs) = go (x + curr) xs |

And let’s look at how this function works much better than before:

1 2 3 4 5 6 7 8 | betterSum [1, 2, 3, 4] go 0 [1, 2, 3, 4] go (1 + 0) [2, 3, 4] go (2 + 1) [3, 4] go (3 + 3) [4] go (4 + 6) [] 4 + 6 ten |

With `&&`

, it is also a function:

1 2 3 | (&&) :: Bool -> Bool -> Bool True && x = x False && _ = False |

We perform the following two operations:

1 2 | False && (10 ^ 1000000> 5) False &&! (10 ^ 1000000> 5) |

The following calculation will be slower because we force `Haskell`

to calculate the value behind while not being needed.

What `Haskell`

compiles and how long it takes to run is hard to predict, remembering the garbage collector so `Haskell`

often not suitable for embedded systems, where memory management and security are needed. absolute latency. Also the source code of a binary binary file from `Haskell`

is very large, so it is not suitable for embedded systems with limited memory. As well as writing an application with `C++`

frameworks like `Qt`

, `Haskell`

in application programming is also very painful. `Haskell`

is best used when creating a `compiler`

, `concurenccy`

or parsing …

The syntax of the language is more mathematical than informatics, for example, to represent a set of even numbers in paragraphs `1`

to `10`

, mathematically, we will write ${x∈1,|2|x}$ or ${x|x∈1,∧2|x}.$ With the second way of writing, we will implement it with `Haskell`

with a simple switch $∈$ to `<-`

:

1 | [x | x <- [1..10], x `mod` 2 == 0] |

The results will return `[2, 4, 6, 8, 10]`

. To list the set of 3 integers without negative numbers with a sum equal to 6, we will have:

1 | [(a, b, c) | a <- [0..6], b <- [0..6], c <- [0..6], a + b + c == 6] |

I learned `Haskell`

just because of this, regression, combinatorial, … formula models can be implemented by Haskell. For example, the problem of counting to see how much the `n`

non-negative integers whose sum is `m`

. Of course according to Euler candy division result will be $(m+n–n–1),$ but let’s pretend naive as to what it was working with Bayes’ theorem in Machine Learning, we will list all into a list and count the number of elements of that list:

1 2 3 | tupleWithSum :: Integer -> Integer -> [[Integer]] tupleWithSum 1 m = [[m]] tupleWithSum nm = [x: xs | x <- [0..m], xs <- tupleWithSum (n - 1) (m - x)] |

We perform `length $ tupleWithSum 3 6`

, the results of `28`

primary by $(8+3-13-1).$ Look at that function and design it with the mathematical model, it will be written $S_{n+1,m}={(x,A)|x∈0,m,A∈S_{n–1,m–x}}$ .

Thanks to `Haskell`

, I learned how to deploy something like `quy hoạch động`

through `đệ quy`

:

1 2 3 4 | fib = go 0 1 where go a _ 0 = a go abn = go b (a + b) (n - 1) |

Overall, `Haskell`

made me more interested than I thought, even though it was difficult, but it was worth studying for programming thinking.

How to choose a programming language is reasonable?

**Source : ** viblo