-
Notifications
You must be signed in to change notification settings - Fork 376
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Single source of truth for everything #158
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -138,11 +138,10 @@ the Semigroup specification. | |
empty :: Monoid m => () -> m | ||
``` | ||
|
||
A value which has a Monoid must provide an `empty` method on itself or | ||
its `constructor` object. The `empty` method takes no arguments: | ||
A value which has a Monoid must provide an `empty` method. The `empty` | ||
method takes no arguments: | ||
|
||
m.empty() | ||
m.constructor.empty() | ||
|
||
1. `empty` must return a value of the same Monoid | ||
|
||
|
@@ -213,11 +212,10 @@ implement the Apply specification. | |
of :: Applicative f => a -> f a | ||
``` | ||
|
||
A value which has an Applicative must provide an `of` method on itself | ||
or its `constructor` object. The `of` method takes one argument: | ||
A value which has an Applicative must provide an `of` method. The `of` | ||
method takes one argument: | ||
|
||
a.of(b) | ||
a.constructor.of(b) | ||
|
||
1. `of` must provide a value of the same Applicative | ||
|
||
|
@@ -254,27 +252,25 @@ implement the Functor and Foldable specifications. | |
1. `t(u.sequence(f.of))` is equivalent to `u.map(t).sequence(g.of)` | ||
for any `t` such that `t(a).map(f)` is equivalent to `t(a.map(f))` (naturality) | ||
|
||
2. `u.map(F.of).sequence(F.of)` is equivalent to `F.of(u)` for any Applicative `F` (identity) | ||
2. `u.map(f.of).sequence(f.of)` is equivalent to `f.of(u)` for any Applicative `f` (identity) | ||
|
||
3. `u.map(x => new Compose(x)).sequence(Compose.of)` is equivalent to | ||
`new Compose(u.sequence(F.of).map(v => v.sequence(G.of)))` for `Compose` defined below and any Applicatives `F` and `G` (composition) | ||
3. `u.map(compose.of).sequence(compose.of)` is equivalent to | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Something wrong here. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'll fix that when I get home to |
||
`compose.create(u.sequence(f.of).map(v => v.sequence(g.of)))` for `Compose` defined below and any Applicatives `f` and `g` (composition) | ||
|
||
```js | ||
var Compose = function(c) { | ||
this.c = c; | ||
}; | ||
|
||
Compose.of = function(x) { | ||
return new Compose(F.of(G.of(x))); | ||
}; | ||
|
||
Compose.prototype.ap = function(x) { | ||
return new Compose(this.c.map(u => y => u.ap(y)).ap(x.c)); | ||
}; | ||
|
||
Compose.prototype.map = function(f) { | ||
return new Compose(this.c.map(y => y.map(f))); | ||
}; | ||
var compose = { | ||
of: function(x) { | ||
return {__proto__: compose, c}; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Really? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would you like a different method of setting the prototype? (Keep in mind, I'm not actually that deeply invested in this. I'm merely encouraging exploration.) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why not rely on the // Identity :: a -> Identity a
var Identity = function Identity(x) {
return {
constructor: {'fantasy-land/of': Identity},
'fantasy-land/chain': function(f) { return f(x); },
'fantasy-land/map': function(f) { return Identity(f(x)); },
// ...
value: x
};
}; The nice thing about this approach is it allows a prototype-based implementation: // Identity :: a -> Identity a
var Identity = function Identity(x) {
if (!(this instanceof Identity)) return new Identity(x);
this.value = x;
};
// Identity.of :: a -> Identity a
Identity['fantasy-land/of'] = Identity;
// Identity#chain :: Identity a ~> (a -> Identity b) -> Identity b
Identity.prototype['fantasy-land/chain'] = function(f) { return f(this.value); };
// Identity#map :: Identity a ~> (a -> b) -> Identity b
Identity.prototype['fantasy-land/map'] = function(f) { return Identity(f(this.value)); };
// ... I don't see a reason to use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
But didn't we want to remove static method? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Anyway if we want to remove static method, I think we should simply remove static method from current implementations, without switching to simple objects or anything. |
||
}, | ||
|
||
ap: function(x) { | ||
return compose.create(this.c.map(u => y => u.ap(y)).ap(x.c)); | ||
}, | ||
|
||
map: function(f) { | ||
return compose.create(this.c.map(y => y.map(f))); | ||
}, | ||
} | ||
``` | ||
|
||
#### `sequence` method | ||
|
@@ -331,11 +327,10 @@ A value that implements the ChainRec specification must also implement the Chain | |
chainRec :: ChainRec m => ((a -> c) -> (b -> c) -> a -> m c) -> a -> m b | ||
``` | ||
|
||
A Type which has a ChainRec must provide an `chainRec` method on itself | ||
or its `constructor` object. The `chainRec` method takes two arguments: | ||
A Type which has a ChainRec must provide an `chainRec` method. The | ||
`chainRec` method takes two arguments: | ||
|
||
a.chainRec(f, i) | ||
a.constructor.chainRec(f, i) | ||
|
||
1. `f` must be a function which returns a value | ||
1. If `f` is not a function, the behaviour of `chainRec` is unspecified. | ||
|
@@ -501,19 +496,23 @@ to implement certain methods then derive the remaining methods. Derivations: | |
|
||
```js | ||
function(f, acc) { | ||
function Const(value) { | ||
this.value = value; | ||
function makeConst(value) { | ||
return {__proto__: constant, value}; | ||
} | ||
Const.of = function(_) { | ||
return new Const(acc); | ||
}; | ||
Const.prototype.map = function(_) { | ||
return this; | ||
}; | ||
Const.prototype.ap = function(b) { | ||
return new Const(f(this.value, b.value)); | ||
|
||
var constant = { | ||
of: function(_) { | ||
return makeConst(acc); | ||
}, | ||
map: function(_) { | ||
return this; | ||
}, | ||
ap: function(b) { | ||
return makeConst(f(this.value, b.value)); | ||
}, | ||
}; | ||
return this.map(x => new Const(x)).sequence(Const.of).value; | ||
|
||
return this.map(makeConst).sequence(constant.of).value; | ||
} | ||
``` | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe we all agree that this change is a good idea. I've opened #162 which makes this change only.