mirror of
https://github.com/rjNemo/functional-programming-jargon
synced 2026-06-06 02:26:43 +00:00
Merge pull request #190 from hekmekk/refactor/totality-and-partial-function
Introduce 'function' section
This commit is contained in:
commit
ca37a0e6d4
1 changed files with 18 additions and 18 deletions
36
readme.md
36
readme.md
|
|
@ -60,7 +60,8 @@ __Table of Contents__
|
||||||
* [Sum type](#sum-type)
|
* [Sum type](#sum-type)
|
||||||
* [Product type](#product-type)
|
* [Product type](#product-type)
|
||||||
* [Option](#option)
|
* [Option](#option)
|
||||||
* [Totality](#totality)
|
* [Function](#function)
|
||||||
|
* [Partial function](#partial-function)
|
||||||
* [Functional Programming Libraries in JavaScript](#functional-programming-libraries-in-javascript)
|
* [Functional Programming Libraries in JavaScript](#functional-programming-libraries-in-javascript)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -908,21 +909,18 @@ getNestedPrice({item: {price: 9.99}}) // Some(9.99)
|
||||||
|
|
||||||
`Option` is also known as `Maybe`. `Some` is sometimes called `Just`. `None` is sometimes called `Nothing`.
|
`Option` is also known as `Maybe`. `Some` is sometimes called `Just`. `None` is sometimes called `Nothing`.
|
||||||
|
|
||||||
## Totality
|
## Function
|
||||||
### Total functions
|
A **function** `f :: A => B` is an expression - often called arrow or lambda expression - with **exactly one (immutable)** parameter of type `A` and **exactly one** return value of type `B`. That value depends entirely on the argument, making functions context-independant, or [referentially transparent](#referential-transparency). What is implied here is that a function must not produce any hidden [side effects](#side-effects) - a function is always [pure](#purity), by definition. These properties make functions pleasant to work with: they are entirely deterministic and therefore predictable. Functions enable working with code as data, abstracting over behaviour:
|
||||||
The total function is just like a function in math - it will always return a result of the expected type for expected inputs and will always terminate. The easiest example is `identity` function:
|
|
||||||
```js
|
```js
|
||||||
// identity :: a -> a
|
// times2 :: Number -> Number
|
||||||
const identity = a => a
|
const times2 = n => n * 2
|
||||||
|
|
||||||
|
[1, 2, 3].map(times2) // [2, 4, 6]
|
||||||
```
|
```
|
||||||
or `negate`:
|
|
||||||
```js
|
## Partial function
|
||||||
// negate :: Boolean -> Boolean
|
A partial function is a [function](#function) which is not defined for all arguments - it might return an unexpected result or may never terminate. Partial functions add cognitive overhead, they are harder to reason about and can lead to runtime errors. Some examples:
|
||||||
const negate = value => !value
|
|
||||||
```
|
|
||||||
Such functions always meet the requirements, you just can't provide such arguments, which satisfy inputs but break outputs.
|
|
||||||
### Partial functions
|
|
||||||
It's a function which violates the requirements to be total - it may return an unexpected result with some inputs or it may never terminate. Partial functions add cognitive overhead, they are harder to reason about and they can lead to runtime errors. Some examples:
|
|
||||||
```js
|
```js
|
||||||
// example 1: sum of the list
|
// example 1: sum of the list
|
||||||
// sum :: [Number] -> Number
|
// sum :: [Number] -> Number
|
||||||
|
|
@ -949,8 +947,10 @@ times(3)(console.log)
|
||||||
times(-1)(console.log)
|
times(-1)(console.log)
|
||||||
// RangeError: Maximum call stack size exceeded
|
// RangeError: Maximum call stack size exceeded
|
||||||
```
|
```
|
||||||
### Avoiding partial functions
|
|
||||||
Partial functions are dangerous, you can sometimes get the expected result, sometimes the wrong result, and sometimes your function can't stop the calculations at all. The input of partial functions should be always checked, and it can be hard to track all edge cases through entire applications, the easiest way to deal with it it's just to convert all partial functions to the total. General advice can be the usage of `Option` type, providing default values for edge cases and checking function conditions to make them always terminate:
|
### Dealing with partial functions
|
||||||
|
Partial functions are dangerous as they need to be treated with great caution. You might get an unexpected (wrong) result or run into runtime errors. Sometimes a partial function might not return at all. Being aware of and treating all these edge cases accordingly can become very tedious.
|
||||||
|
Fortunately a partial function can be converted to a regular (or total) one. We can provide default values or use guards to deal with inputs for which the (previously) partial function is undefined. Utilizing the [`Option`](#Option) type, we can yield either `Some(value)` or `None` where we would otherwise have behaved unexpectedly:
|
||||||
```js
|
```js
|
||||||
// example 1: sum of the list
|
// example 1: sum of the list
|
||||||
// we can provide default value so it will always return result
|
// we can provide default value so it will always return result
|
||||||
|
|
@ -963,7 +963,7 @@ sqrt([]) // 0
|
||||||
// change result to Option
|
// change result to Option
|
||||||
// first :: [A] -> Option A
|
// first :: [A] -> Option A
|
||||||
const first = a => a.length ? Some(a[0]) : None()
|
const first = a => a.length ? Some(a[0]) : None()
|
||||||
first([[42]]).map(a => console.log(a)) // 42
|
first([42]).map(a => console.log(a)) // 42
|
||||||
first([]).map(a => console.log(a)) // console.log won't execute at all
|
first([]).map(a => console.log(a)) // console.log won't execute at all
|
||||||
//our previous worst case
|
//our previous worst case
|
||||||
first([[42]]).map(a => console.log(a[0])) // 42
|
first([[42]]).map(a => console.log(a[0])) // 42
|
||||||
|
|
@ -983,7 +983,7 @@ times(3)(console.log)
|
||||||
times(-1)(console.log)
|
times(-1)(console.log)
|
||||||
// won't execute anything
|
// won't execute anything
|
||||||
```
|
```
|
||||||
If you will change all your functions from partial to total, it can prevent you from having runtime exceptions, will make code easier to reason about and easier to maintain.
|
Making your partial functions total ones, these kinds of runtime errors can be prevented. Always returning a value will also make for code that is both easier to maintain as well as to reason about.
|
||||||
|
|
||||||
## Functional Programming Libraries in JavaScript
|
## Functional Programming Libraries in JavaScript
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue