-
Notifications
You must be signed in to change notification settings - Fork 377
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
Add Alt, Plus and Alternative specs #197
Changes from 9 commits
27fe5ca
0903767
68e6b42
69655f7
98e3634
2863e8c
05f01ac
cb5977d
7e661ed
09798ee
05fe7c4
5edc75c
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 |
---|---|---|
|
@@ -15,6 +15,9 @@ structures: | |
* [Functor](#functor) | ||
* [Apply](#apply) | ||
* [Applicative](#applicative) | ||
* [Alt](#alt) | ||
* [Plus](#plus) | ||
* [Alternative](#alternative) | ||
* [Foldable](#foldable) | ||
* [Traversable](#traversable) | ||
* [Chain](#chain) | ||
|
@@ -25,7 +28,7 @@ structures: | |
* [Bifunctor](#bifunctor) | ||
* [Profunctor](#profunctor) | ||
|
||
<img src="figures/dependencies.png" width="863" height="347" /> | ||
<img src="figures/dependencies.png" width="100%" /> | ||
|
||
## General | ||
|
||
|
@@ -243,6 +246,69 @@ Given a value `f`, one can access its type representative via the | |
|
||
1. No parts of `a` should be checked | ||
|
||
### Alt | ||
|
||
A value that implements the Alt specification must also implement | ||
the [Functor](#functor) specification. | ||
|
||
1. `a.alt(b).alt(c)` is equivalent to `a.alt(b.alt(c))` (associativity) | ||
2. `a.alt(b).map(f)` is equivalent to `a.map(f).alt(b.map(f))` (distributivity) | ||
|
||
#### `alt` method | ||
|
||
```hs | ||
alt :: Alt f => f a ~> f a -> f a | ||
``` | ||
|
||
A value which has a Alt must provide a `alt` method. The | ||
`alt` method takes one argument: | ||
|
||
a.alt(b) | ||
|
||
1. `b` must be a value of the same Alt | ||
|
||
1. If `b` is not the same Alt, behaviour of `alt` is | ||
unspecified. | ||
2. `a` and `b` can contain any value of same type. | ||
3. No parts of `a`'s and `b`'s containing value should be checked. | ||
|
||
2. `alt` must return a value of the same Alt. | ||
|
||
### Plus | ||
|
||
A value that implements the Plus specification must also implement | ||
the [Alt](#alt) specification. | ||
|
||
1. `x.alt(A.zero())` is equivalent to `x` (right identity) | ||
2. `A.zero().alt(x)` is equivalent to `x` (left identity) | ||
2. `A.zero().map(f)` is equivalent to `A.zero()` (annihilation) | ||
|
||
#### `zero` method | ||
|
||
```hs | ||
zero :: Plus x => () -> x | ||
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. Should it be 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. In that case we should also add 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 think 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 would use |
||
``` | ||
|
||
A value which has a Plus must provide an `zero` function on its | ||
[type representative](#type-representatives): | ||
|
||
A.zero() | ||
|
||
Given a value `x`, one can access its type representative via the | ||
`constructor` property: | ||
|
||
x.constructor.zero() | ||
|
||
1. `zero` must return a value of the same Plus | ||
|
||
### Alternative | ||
|
||
A value that implements the Alternative specification must also implement | ||
the [Applicative](#applicative) and [Plus](#plus) specifications. | ||
|
||
1. `x.ap(f.alt(g))` is equivalent to `x.ap(f).alt(x.ap(g))` (distributivity) | ||
1. `x.ap(A.zero())` is equivalent to `A.zero()` (annihilation) | ||
|
||
### Foldable | ||
|
||
1. `u.reduce` is equivalent to `u.reduce((acc, x) => acc.concat([x]), []).reduce` | ||
|
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
'use strict'; | ||
|
||
const {tagged} = require('daggy'); | ||
|
||
const fl = require('..'); | ||
const {equality} = require('./func'); | ||
|
||
const Compose = module.exports = tagged('c'); | ||
Compose[fl.of] = Compose; | ||
Compose.prototype[fl.ap] = function(f) { | ||
return Compose(this.c[fl.ap](f.c[fl.map](u => y => y[fl.ap](u)))); | ||
}; | ||
Compose.prototype[fl.map] = function(f) { | ||
return Compose(this.c[fl.map](y => y[fl.map](f))); | ||
}; | ||
Compose.prototype[fl.equals] = function(x) { | ||
return equality(this.c, x.c); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
'use strict'; | ||
|
||
const fl = require('../'); | ||
const equality = (x, y) => typeof x[fl.equals] === 'function' ? x[fl.equals](y) : x === y; | ||
|
||
module.exports = { | ||
equality, | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
'use strict'; | ||
|
||
const patch = require('./patch'); | ||
const Id = require('./id'); | ||
const Sum = require('./string_sum'); | ||
const Compose = require('./compose'); | ||
const {equality} = require('./func'); | ||
|
||
module.exports = { | ||
Id, | ||
Sum, | ||
Compose, | ||
equality, | ||
patch, | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
'use strict'; | ||
|
||
const fl = require('..'); | ||
|
||
module.exports = () => { | ||
String.prototype[fl.concat] = String.prototype.concat; | ||
Array.prototype[fl.equals] = function(y) { | ||
return this.length === y.length && this.join('') === y.join(''); | ||
}; | ||
Array.prototype[fl.map] = Array.prototype.map; | ||
Array.prototype[fl.ap] = function(fs) { | ||
return fs[fl.chain](f => this.map(f)); | ||
}; | ||
Array.prototype[fl.chain] = function(f) { | ||
return [].concat(this.map(f)); | ||
}; | ||
Array.prototype[fl.reduce] = Array.prototype.reduce; | ||
Array.prototype[fl.concat] = Array.prototype.concat; | ||
Array.prototype[fl.traverse] = function(f, p) { | ||
return this.map(f)[fl.reduce]( | ||
(ys, x) => ys[fl.ap](x[fl.map](y => z => z[fl.concat](y))), | ||
p([]) | ||
); | ||
}; | ||
Array.prototype[fl.alt] = function(b) { | ||
return this.concat(b); | ||
}; | ||
Array[fl.zero] = () => []; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
'use strict'; | ||
|
||
const {tagged} = require('daggy'); | ||
|
||
const fl = require('..'); | ||
const {equality} = require('./func'); | ||
|
||
// Special type of sum for the type of string. | ||
const Sum = module.exports = tagged('v'); | ||
Sum[fl.of] = Sum; | ||
Sum[fl.empty] = () => Sum(''); | ||
Sum.prototype[fl.map] = function(f) { | ||
return Sum(f(this.v)); | ||
}; | ||
Sum.prototype[fl.concat] = function(x) { | ||
return Sum(this.v + x.v); | ||
}; | ||
Sum.prototype[fl.equals] = function(x) { | ||
return equality(this.v, x.v); | ||
}; |
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 think this will reintroduce the problem @rpominov fixed in #119.
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.
Will fix that. We definitly need CONTRIBUTING.md
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.
on github the width of README is fixed but for example on npm it looks bad because max width of readme area is 727px and if you are on small screan than it's worth.
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.
Yeah, same issue with mobile version of GitHub for example. I wish we could find a fix without this side effect, but in the current situation having links to point to the right locations is more important imo.
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.
Ok will change it as it was before.
But we could move the image to the end of README and have a link in it's place where it was before (next to list of specs) and also a link back.
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.
+1 for moving to the end.
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.
you can check rendered image here