Add more morphisms

I was watching @DrBoolean's [A Million Ways to Fold in JS](https://www.youtube.com/watch?v=JZSoPZUoR58) but I couldn't understand most of the morphism jargons. I presume the video is for experienced devs who are from a FP language background. The moment when I tried to search for "Catamorphism javascript" on google I couldn't get anything. I really hope there would be more in depth FP resources written in JavaScript. Luckily @i-am-tom kindly wrote up something that could be understood by JS devs like me. I have fixed a minor mistake in @i-am-tom's [original write up](https://github.com/DrBoolean/RecursionTalk/issues/2#issuecomment-292777148) and tweaked a few wording.

Also cc @joneshf @getify @shineli1984

Thanks!
This commit is contained in:
Steve Mao 2017-04-10 20:16:44 +10:00
parent 273175df14
commit 5071b5a617
No known key found for this signature in database
GPG key ID: EED733AB250010C0

View file

@ -51,6 +51,11 @@ __Table of Contents__
* [Morphism](#morphism) * [Morphism](#morphism)
* [Endomorphism](#endomorphism) * [Endomorphism](#endomorphism)
* [Isomorphism](#isomorphism) * [Isomorphism](#isomorphism)
* [Catamorphism](#catamorphism)
* [Anamorphism](#anamorphism)
* [Hylomorphism](#hylomorphism)
* [Paramorphism](#paramorphism)
* [Apomorphism](#apomorphism)
* [Setoid](#setoid) * [Setoid](#setoid)
* [Semigroup](#semigroup) * [Semigroup](#semigroup)
* [Foldable](#foldable) * [Foldable](#foldable)
@ -691,7 +696,70 @@ coordsToPair(pairToCoords([1, 2])) // [1, 2]
pairToCoords(coordsToPair({x: 1, y: 2})) // {x: 1, y: 2} pairToCoords(coordsToPair({x: 1, y: 2})) // {x: 1, y: 2}
``` ```
### Catamorphism
A `reduceRight` function. Take a bunch of things, and combine them into another. The morphism is from "bunch of things" to "another".
```js
const sum = xs => xs.reduceRight((acc, x) => acc + x, 0)
sum([1, 2, 3, 4, 5]) // 15
```
### Anamorphism
An `unfold` function. An `unfold` is the opposite of `fold` (`reduce`). It generates a list from a single value.
```js
const unfold = (f, seed) => {
function go(f, seed, acc) {
const res = f(seed);
return res ? go(f, res[1], acc.concat([res[0]])) : acc;
}
return go(f, seed, [])
}
```
```js
const countDown = n => unfold((n) => {
return n <= 0 ? undefined : [n, n - 1]
}, n)
countDown(5) // [5, 4, 3, 2, 1]
```
### Hylomorphism
The combination of anamorphism and catamorphism.
### Paramorphism
Enhancement of catamorphism. It's like `reduceRight`. However, there's a difference:
In paramorphism, your reducer's arguments are the current value, the reduction of all previous values, and the list of values that formed that reduction.
```js
// Obviously not safe for lists containing `undefined`,
// but good enough to make the point.
const para = (reducer, accumulator, [x, ... xs]) =>
x !== undefined
? reducer(x, xs, para(reducer, accumulator, xs))
: accumulator
const suffixes = list => para(
(x, xs, suffxs) => [xs, ... suffxs],
[],
list
)
suffixes([1, 2, 3, 4, 5]) // [[2, 3, 4, 5], [3, 4, 5], [4, 5], [5], []]
```
The third parameter in the reducer (in the above example, `[x, ... xs]`) is kind of like having a history of what got you to your current acc value.
### Apomorphism
it's the opposite of paramorphism, just as anamorphism is the opposite of catamorphism. Whereas with paramorphism, you combine with access to the accumulator and what has been accumulated, apomorphism lets you `unfold` with the potential to return early.
## Setoid ## Setoid