From 0a9c2169ef8a3fc4ab64463eb091805d73f38d01 Mon Sep 17 00:00:00 2001 From: jethro larson Date: Sat, 20 Feb 2016 14:55:35 -0800 Subject: [PATCH 1/5] Updated Isomorphic and Monad. --- readme.md | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/readme.md b/readme.md index 5abbdda..a61b214 100644 --- a/readme.md +++ b/readme.md @@ -269,12 +269,27 @@ The identity value is empty array `[]` ## Monad -> A monad is a container type that provides two functions, [chain](#chain) and [ap](#applicative-functor). Monads provide an interface for executing a common sequence of commands on a particular kind of value, often one you want to avoid acting on directly. One of the most common monads is the "maybe" or optional value monad, which wraps a value that could be either nothing or something. By using a monad instead of the raw value, you can protect your code from exposure to null values. Likewise, a "state" monad can be used in a parser to algorithmically consume an input string using a repeatable sequence of steps that preserves the current state of the input from operation to operation. Also, since a monad is, by definition, a special kind of functor that also returns a monad, they can be chained together to describe any sequence of operations. In functional languages with lazy evaluation, monads are used where sequence of evaluation is important, such as in I/O. Due to this sequencing utility, they are sometimes referred to as "programmable semicolons." +> A monad is a container type that provides two functions, [chain](#chain) and `of`. Monads provide an interface for executing a common sequence of commands on a particular kind of value, often one you want to avoid acting on directly. One of the most common monads is the "maybe" or optional value monad, which wraps a value that could be either nothing or something. By using a monad instead of the raw value, you can protect your code from exposure to null values. Likewise, a "state" monad can be used in a parser to algorithmically consume an input string using a repeatable sequence of steps that preserves the current state of the input from operation to operation. Also, since a monad is, by definition, a special kind of functor that also returns a monad, they can be chained together to describe any sequence of operations. In functional languages with lazy evaluation, monads are used where sequence of evaluation is important, such as in I/O. Due to this sequencing utility, they are sometimes referred to as "programmable semicolons." The simplest monad is the Identity monad. It simply wraps a value. ```js -let Identity = v => ({ chain: transform => transform(v) }) +let Identity = v => ({ + val: v, + chain: transform => transform(this.val), + of: v => this.val +}) + +// Function that increments value and then wraps with Identity. +let increment = v => Identity(v + 1) + +// Use chain to apply function to wrapped values +let incrementIdentity = id => id.chain(increment) + +incrementIdentity(Identity(1)) // Identity(2) + +//Contrast to using a map, where increment would cause nested Identities +id.map(increment) // Identity(Identity(2)) ``` --- @@ -309,16 +324,16 @@ let Identity = v => ({ chain: transform => transform(v) }) ## Isomorphic -> Two objects are Isomorphic is they satisfy the condition: `compose(to, from) == Identity` and `compose(from, to) == Identity` +> Two objects are Isomorphic is they satisfy the condition: `compose(to, from) == identity` and `compose(from, to) == identity` ```js -const toChars = [].join; +const pairToCoords = (arr) => ({x: arr[0], y: arr[1]}) -const fromChars = ''.split; +const coordsToPair = (coords) => [coords.x, coords.y] -fromChars.call(toChars.call([1,2,3])) // [ '1,2,3' ] +coordsToPair(pairToCoords([1, 2])) // [1, 2] -toChars.call(fromChars.call([1,2,3])) // '1,2,3' +pairToCoords(coordsToPair({x: 1, y: 2})) // {x: 1, y: 2} ``` --- From ee69aed8091f0d668a9b16232e26f2cd335a6262 Mon Sep 17 00:00:00 2001 From: jethro larson Date: Sat, 20 Feb 2016 15:09:47 -0800 Subject: [PATCH 2/5] Fixed errors and inconsistencies with point-free --- readme.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/readme.md b/readme.md index a61b214..b7f2920 100644 --- a/readme.md +++ b/readme.md @@ -133,13 +133,13 @@ let add = (a, b) => a + b; // Not points-free - `numbers` is an explicit parameter let incrementAll = (numbers) => map(add(1))(numbers); -// Points-free - The array is an implicit parameter +// Points-free - The list is an implicit parameter let incrementAll2 = map(add(1)); ``` -`total1` lists and uses the parameter `numbers`, so it is not points-free. `total2` is written just by combining functions and values, making no mention of its arguments. It __is__ points-free. +`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. -It is easy to recognize points-free function definitions; they are the ones that contain no '`function`' keywords and no fat arrows. +Points-free function definitions look just like normal assignments without `function` or `=>`. --- From e27905d33489c8f0fa1d1f273dabdb935f6902a8 Mon Sep 17 00:00:00 2001 From: jethro larson Date: Sat, 20 Feb 2016 15:33:57 -0800 Subject: [PATCH 3/5] Attempted to define type signature comments. --- readme.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/readme.md b/readme.md index b7f2920..cd250c0 100644 --- a/readme.md +++ b/readme.md @@ -357,3 +357,29 @@ pairToCoords(coordsToPair({x: 1, y: 2})) // {x: 1, y: 2} ## Comonad --- +## Type Signatures + +> Often functions will include comments that indicate the types of their arguments and return types. + +There's quite a bit variance across the community but they often follow the following patterns: +```js +// functionName :: firstArgType -> secondArgType -> returnType + +// add :: Number -> Number -> Number +let add = x => y => x + y + +// increment :: Number -> Number +let increment = x => x + 1 +``` + +If a function accepts another function as an argument it is wrapped in parenthesis. + +```js +// call :: (a -> b) -> a -> b +let call = f => x => f(x) +``` +The letters `a`, `b`, `c`, `d` are used to signify that the argument can be of any type. For this map it takes a function that transforms a value of some type `a` into another type `b`, an array of values of type `a`, and returns an array of values of type `b`. +```js +// map :: (a -> b) -> [a] -> [b] +let map = f => list => list.map(f) +``` From 6913df8f932c1d66039816ae38b10c82ed93b47c Mon Sep 17 00:00:00 2001 From: jethro larson Date: Sat, 20 Feb 2016 18:05:27 -0800 Subject: [PATCH 4/5] Attempted comonad, setoid, and foldable. --- readme.md | 51 +++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 47 insertions(+), 4 deletions(-) diff --git a/readme.md b/readme.md index cd250c0..59c3ab0 100644 --- a/readme.md +++ b/readme.md @@ -306,6 +306,25 @@ id.map(increment) // Identity(Identity(2)) ## Comonad +> A container type that has `extract` and `extend` functions. + +```js +let CoIdentity = v => ({ + val: v, + extract: this.v, + extend: f => f(this) +}) +``` + +Extract takes a value out of a container. Essentially it's the opposite of `of`. +```js +CoIdentity(1).extract() // 1 +``` + +Extend runs a function on the comonad. The function should return the same type as the value in the Comonad. It's the opposite of `chain`. +```js +CoIdentity(1).extend(co => co.extract() + 1) // 2 +``` --- ## Applicative Functor @@ -340,6 +359,27 @@ pairToCoords(coordsToPair({x: 1, y: 2})) // {x: 1, y: 2} ## Setoid +> An object that has an `equals` function which can be used to compare other objects of the same type. + +Make array a setoid. +```js +Array.prototype.equals = arr => { + var len = this.length + if (len != arr.length) { + return false + } + for (var i = 0; i < len; i++) { + if (this[i] !== arr[i]) { + return false + } + } + return true +} + +[1, 2].equals([1, 2]) // true +[1, 2].equals([0]) // false +``` + --- ## Semigroup @@ -348,14 +388,17 @@ pairToCoords(coordsToPair({x: 1, y: 2})) // {x: 1, y: 2} ## Foldable +> An object that has a reduce function that can transform that object into some other type. + +```js +let sum = list => list.reduce((acc, val) => acc + val, 0); +sum([1, 2, 3]) // 6 +``` + --- ## Traversable ---- - -## Comonad - --- ## Type Signatures From ed415a1003e50e3dc0d4c6954c1f4b84046e17a1 Mon Sep 17 00:00:00 2001 From: jethro larson Date: Sat, 20 Feb 2016 23:03:05 -0800 Subject: [PATCH 5/5] Added basic description of semigroup. Fixed comonad --- readme.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/readme.md b/readme.md index 59c3ab0..8861adb 100644 --- a/readme.md +++ b/readme.md @@ -65,7 +65,7 @@ partial(2); //=> 42 > The process of converting a function with multiple arity into the same function with an arity of one. Not to be confused with partial application, which can produce a function with an arity greater than one. ```js -let sum = (a,b) => a+b; +let sum = (a, b) => a + b; let curriedSum = (a) => (b) => a + b; @@ -321,9 +321,9 @@ Extract takes a value out of a container. Essentially it's the opposite of `of`. CoIdentity(1).extract() // 1 ``` -Extend runs a function on the comonad. The function should return the same type as the value in the Comonad. It's the opposite of `chain`. +Extend runs a function on the comonad. The function should return the same type as the Comonad. ```js -CoIdentity(1).extend(co => co.extract() + 1) // 2 +CoIdentity(1).extend(co => co.extract() + 1) // CoIdentity(2) ``` --- @@ -384,6 +384,12 @@ Array.prototype.equals = arr => { ## Semigroup +An object that has a `concat` function that combines it with another object of the same type. + +```js +[1].concat([2]) // [1, 2] +``` + --- ## Foldable