Skip to content

Commit e29c470

Browse files
jethro larsonjethrolarson
authored andcommitted
Improved some definitions and added examples
1 parent ffc2217 commit e29c470

File tree

1 file changed

+92
-39
lines changed

1 file changed

+92
-39
lines changed

readme.md

Lines changed: 92 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ __Table of Contents__
3030
* [Auto Currying](#auto-currying)
3131
* [Function Composition](#function-composition)
3232
* [Continuation](#continuation)
33-
* [Purity](#purity)
33+
* [Pure Function](#pure-function)
3434
* [Side effects](#side-effects)
3535
* [Idempotent](#idempotent)
3636
* [Point-Free Style](#point-free-style)
@@ -39,6 +39,9 @@ __Table of Contents__
3939
* [Category](#category)
4040
* [Value](#value)
4141
* [Constant](#constant)
42+
* [Constant Function](#constant-function)
43+
* [Constant Functor](#constant-functor)
44+
* [Constant Monad](#constant-monad)
4245
* [Functor](#functor)
4346
* [Pointed Functor](#pointed-functor)
4447
* [Lift](#lift)
@@ -78,16 +81,20 @@ __Table of Contents__
7881

7982
## Arity
8083

81-
The number of arguments a function takes. From words like unary, binary, ternary, etc. This word has the distinction of being composed of two suffixes, "-ary" and "-ity." Addition, for example, takes two arguments, and so it is defined as a binary function or a function with an arity of two. Such a function may sometimes be called "dyadic" by people who prefer Greek roots to Latin. Likewise, a function that takes a variable number of arguments is called "variadic," whereas a binary function must be given two and only two arguments, currying and partial application notwithstanding (see below).
84+
The number of arguments a function takes. From words like unary, binary, ternary, etc.
8285

8386
```js
8487
const sum = (a, b) => a + b
88+
// The arity of sum is 2 (binary)
89+
const inc = a => a + 1
90+
// The arity of inc is 1 (unary)
91+
const zero = () => 0
92+
// The arity of zero is 0 (nullary)
93+
```
8594

86-
const arity = sum.length
87-
console.log(arity) // 2
95+
__Further reading__
8896

89-
// The arity of sum is 2
90-
```
97+
* [Arity](https://en.wikipedia.org/wiki/Arity) on wikipedia.
9198

9299
## Higher-Order Functions (HOF)
93100

@@ -107,29 +114,18 @@ filter(is(Number), [0, '1', 2, null]) // [0, 2]
107114

108115
## Closure
109116

110-
A closure is a way of accessing a variable outside its scope.
111-
Formally, a closure is a technique for implementing lexically scoped named binding. It is a way of storing a function with an environment.
112-
113117
A closure is a scope which captures local variables of a function for access even after the execution has moved out of the block in which it is defined.
114-
ie. they allow referencing a scope after the block in which the variables were declared has finished executing.
118+
This allows the values in the closure to be accessed by returned functions.
115119

116120

117121
```js
118122
const addTo = x => y => x + y
119123
var addToFive = addTo(5)
120-
addToFive(3) // returns 8
124+
addToFive(3) // => 8
121125
```
122-
The function ```addTo()``` returns a function(internally called ```add()```), lets store it in a variable called ```addToFive``` with a curried call having parameter 5.
123-
124-
Ideally, when the function ```addTo``` finishes execution, its scope, with local variables add, x, y should not be accessible. But, it returns 8 on calling ```addToFive()```. This means that the state of the function ```addTo``` is saved even after the block of code has finished executing, otherwise there is no way of knowing that ```addTo``` was called as ```addTo(5)``` and the value of x was set to 5.
125-
126-
Lexical scoping is the reason why it is able to find the values of x and add - the private variables of the parent which has finished executing. This value is called a Closure.
127126

128-
The stack along with the lexical scope of the function is stored in form of reference to the parent. This prevents the closure and the underlying variables from being garbage collected(since there is at least one live reference to it).
129-
130-
Lambda Vs Closure: A lambda is essentially a function that is defined inline rather than the standard method of declaring functions. Lambdas can frequently be passed around as objects.
131-
132-
A closure is a function that encloses its surrounding state by referencing fields external to its body. The enclosed state remains across invocations of the closure.
127+
In this case the `x` is retained in `addToFive`'s closure with the value `5`. `addToFive` can then be called with the `y`
128+
to get back the sum.
133129

134130
__Further reading/Sources__
135131
* [Lambda Vs Closure](http://stackoverflow.com/questions/220658/what-is-the-difference-between-a-closure-and-a-lambda)
@@ -139,7 +135,6 @@ __Further reading/Sources__
139135

140136
Partially applying a function means creating a new function by pre-filling some of the arguments to the original function.
141137

142-
143138
```js
144139
// Helper to create partially applied functions
145140
// Takes a function and some arguments
@@ -206,7 +201,7 @@ __Further reading__
206201

207202
## Function Composition
208203

209-
The act of putting two functions together to form a third function where the output of one function is the input of the other.
204+
The act of putting two functions together to form a third function where the output of one function is the input of the other. This is one of the most important ideas of functional programming.
210205

211206
```js
212207
const compose = (f, g) => (a) => f(g(a)) // Definition
@@ -245,10 +240,9 @@ readFileAsync('path/to/file', (err, response) => {
245240
})
246241
```
247242

248-
## Purity
243+
## Pure Function
249244

250-
A function is pure if the return value is only determined by its
251-
input values, and does not produce side effects.
245+
A function is pure if the return value is only determined by its input values, and does not produce side effects. The function must always return the same result when given the same input.
252246

253247
```js
254248
const greet = (name) => `Hi, ${name}`
@@ -297,10 +291,6 @@ console.log('IO is a side effect!')
297291

298292
A function is idempotent if reapplying it to its result does not produce a different result.
299293

300-
```
301-
f(f(x)) ≍ f(x)
302-
```
303-
304294
```js
305295
Math.abs(Math.abs(10))
306296
```
@@ -320,16 +310,14 @@ const add = (a) => (b) => a + b
320310

321311
// Then
322312

323-
// Not points-free - `numbers` is an explicit argument
313+
// Not point-free - `numbers` is an explicit argument
324314
const incrementAll = (numbers) => map(add(1))(numbers)
325315

326-
// Points-free - The list is an implicit argument
316+
// Point-free - The list is an implicit argument
327317
const incrementAll2 = map(add(1))
328318
```
329319

330-
`incrementAll` identifies and uses the parameter `numbers`, so it is not points-free. `incrementAll2` is written just by combining functions and values, making no mention of its arguments. It __is__ points-free.
331-
332-
Points-free function definitions look just like normal assignments without `function` or `=>`.
320+
Point-free function definitions look just like normal assignments without `function` or `=>`. It's worth mentioning that point-free functions are not necessarily better than their counterparts, as they can be more difficult to understand when complex.
333321

334322
## Predicate
335323
A predicate is a function that returns true or false for a given value. A common use of a predicate is as the callback for array filter.
@@ -376,6 +364,27 @@ To be a valid category 3 rules must be met:
376364

377365
Since these rules govern composition at very abstract level, category theory is great at uncovering new ways of composing things.
378366

367+
As an example we can define a category Max as a class
368+
```js
369+
370+
class Max {
371+
constructor (a) {
372+
this.a = a
373+
}
374+
id () {
375+
return this
376+
}
377+
compose (b) {
378+
return this.a > b.a ? this : b
379+
}
380+
toString () {
381+
return `Max(${this.a})`
382+
}
383+
}
384+
385+
new Max(2).compose(new Max(3)).compose(new Max(5)).id().id() // => Max(5)
386+
```
387+
379388
__Further reading__
380389

381390
* [Category Theory for Programmers](https://bartoszmilewski.com/2014/10/28/category-theory-for-programmers-the-preface/)
@@ -409,9 +418,35 @@ With the above two constants the following expression will always return `true`.
409418
john.age + five === ({name: 'John', age: 30}).age + (5)
410419
```
411420

421+
### Constant Function
422+
423+
A [curried](#currying) function that ignores its second argument:
424+
425+
```js
426+
const constant = a => () => a;
427+
428+
[1, 2].map(constant(0)) // => [0, 0]
429+
```
430+
431+
### Constant Functor
432+
433+
Object whose `map` doesn't transform the contents. See [Functor](#functor)
434+
435+
```js
436+
Constant(1).map(n => n + 1) // => Constant(1)
437+
```
438+
439+
### Constant Monad
440+
441+
Object whose `chain` doesn't transform the contents. See [Monad](#monad)
442+
443+
```js
444+
Constant(1).chain(n => Constant(n + 1)) // => Constant(1)
445+
```
446+
412447
## Functor
413448

414-
An object that implements a `map` function which, while running over each value in the object to produce a new object, adheres to two rules:
449+
An object that implements a `map` function that takes a function which is run on the contents of that object. A functor must adhere to two rules:
415450

416451
__Preserves identity__
417452
```
@@ -477,24 +512,42 @@ lift(increment)([2]) // [3]
477512
;[2].map(increment) // [3]
478513
```
479514

515+
Lifting simple values can be simply creating the object.
516+
517+
```js
518+
Array.of(1) // => [1]
519+
```
520+
480521

481522
## Referential Transparency
482523

483524
An expression that can be replaced with its value without changing the
484525
behavior of the program is said to be referentially transparent.
485526

486-
Say we have function greet:
527+
Given the function greet:
487528

488529
```js
489530
const greet = () => 'Hello World!'
490531
```
491532

492533
Any invocation of `greet()` can be replaced with `Hello World!` hence greet is
493-
referentially transparent.
534+
referentially transparent. This would be broken if greet depended on external
535+
state like configuration or a database call. See also [Pure Function](#pure-function) and
536+
[Equational Reasoning](#equational-reasoning).
494537

495538
## Equational Reasoning
496539

497-
When an application is composed of expressions and devoid of side effects, truths about the system can be derived from the parts.
540+
When an application is composed of expressions and devoid of side effects,
541+
truths about the system can be derived from the parts. You can also be confident
542+
about details of your system without having to go through every function.
543+
544+
```js
545+
const grainToDogs = compose(chickenIntoDogs, grainIntoChicken)
546+
const grainToCats = compose(dogsIntoCats, grainToDogs)
547+
```
548+
In the example above, if you know that `chickenIntoDogs` and `grainIntoChicken`
549+
are pure then you know that the composition is pure. This can be taken further
550+
when more is known about the functions (associative, communtative, idempotent, etc...)
498551

499552
## Lambda
500553

0 commit comments

Comments
 (0)