Skip to content

Instantly share code, notes, and snippets.

@ForbesLindesay
Last active January 4, 2022 22:41
Show Gist options
  • Select an option

  • Save ForbesLindesay/5392337 to your computer and use it in GitHub Desktop.

Select an option

Save ForbesLindesay/5392337 to your computer and use it in GitHub Desktop.

Revisions

  1. ForbesLindesay revised this gist Apr 22, 2013. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion Real World Specification.md
    Original file line number Diff line number Diff line change
    @@ -48,7 +48,7 @@ If an entity (call it `A`) implements a method `map` then when it is passed one
    `map` must also obey the following two rules:

    1. `A.map(function (a) { return a; })` is equivalent to `A` ( _identity_ )
    2. `A.map(function (x) { return f(g(x)); })` is equivalent to `u.map(g).map(f)` ( _composition_ )
    2. `A.map(function (x) { return f(g(x)); })` is equivalent to `A.map(g).map(f)` ( _composition_ )

    A practical example of how `map` might be implemented is the array, which calls map for each element in the array and returns a new array that is an array of the results of the function, e.g.:

  2. ForbesLindesay revised this gist Apr 20, 2013. 1 changed file with 5 additions and 5 deletions.
    10 changes: 5 additions & 5 deletions Real World Specification.md
    Original file line number Diff line number Diff line change
    @@ -32,14 +32,14 @@ If an entity (call it `A`) implements a method `concat` then when it is passed o

    ( _an entity that implements `concat` is also known as a 'semigroup' in functional programming_ )

    ### A.constructor.zero()
    ### A.constructor.empty()

    Any entity that implements `zero` must also implement `concat`. `A.constructor.zero()` must return an entity of the same class as `A` which obeys the following two rules.
    Any entity that implements `empty` must also implement `concat`. `A.constructor.empty()` must return an entity of the same class as `A` which obeys the following two rules.

    1. `A` is equivalent to `A.concat(A.constructor.zero())` ( _right identity_ )
    2. `A` is equivalent to `A.constructor.zero().concat(A)` ( _left identity_ )
    1. `A` is equivalent to `A.concat(A.constructor.empty())` ( _right identity_ )
    2. `A` is equivalent to `A.constructor.empty().concat(A)` ( _left identity_ )

    ( _an entity that implements `zero` is also known as a 'monoid' in functional programming_ )
    ( _an entity that implements `empty` is also known as a 'monoid' in functional programming_ )

    ### A.map(fn)

  3. ForbesLindesay revised this gist Apr 16, 2013. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion Real World Specification.md
    Original file line number Diff line number Diff line change
    @@ -77,7 +77,7 @@ It must also obey the rule:
    Any entity that implements `of` must also implement `chain`. `A.constructor.of(B)` must return an entity of the same class as `A` which obeys the following three rules.

    1. If `f` is a function that returns an entity of class `A`, then `A.of(b).chain(f)` is equivalent to `f(b)` ( _left identity_ )
    2. `A.chain(A.constructor.of)` is equivalent to `A` (_right identity_)
    2. `A.chain(A.constructor.of)` is equivalent to `A` ( _right identity_ )
    3. Nothing about the contents of `A` may be checked, it is to be treated as an opaque value

    ( _an entity that implements `of` is also known as a 'monad' in functional programming_ )
  4. ForbesLindesay revised this gist Apr 16, 2013. 1 changed file with 11 additions and 11 deletions.
    22 changes: 11 additions & 11 deletions Real World Specification.md
    Original file line number Diff line number Diff line change
    @@ -28,27 +28,27 @@ Examples:
    If an entity (call it `A`) implements a method `concat` then when it is passed one argument that is of the same class as `A` it must:

    1. return a value with the same type as `A` (the object on which the method was called).
    2. It must be associative. That is to say `a.concat(b).concat(c)` must be equivalent to `a.concat(b.concat(c))` (_associativity_)
    2. It must be associative. That is to say `a.concat(b).concat(c)` must be equivalent to `a.concat(b.concat(c))` ( _associativity_ )

    (_an entity that implements `concat` is also known as a 'semigroup' in functional programming_)
    ( _an entity that implements `concat` is also known as a 'semigroup' in functional programming_ )

    ### A.constructor.zero()

    Any entity that implements `zero` must also implement `concat`. `A.constructor.zero()` must return an entity of the same class as `A` which obeys the following two rules.

    1. `A` is equivalent to `A.concat(A.constructor.zero())` (_right identity_)
    2. `A` is equivalent to `A.constructor.zero().concat(A)` (_left identity_)
    1. `A` is equivalent to `A.concat(A.constructor.zero())` ( _right identity_ )
    2. `A` is equivalent to `A.constructor.zero().concat(A)` ( _left identity_ )

    (_an entity that implements `zero` is also known as a 'monoid' in functional programming_)
    ( _an entity that implements `zero` is also known as a 'monoid' in functional programming_ )

    ### A.map(fn)

    If an entity (call it `A`) implements a method `map` then when it is passed one argument that is a function, map must return an entity of the same class as `A`.

    `map` must also obey the following two rules:

    1. `A.map(function (a) { return a; })` is equivalent to `A` (_identity_)
    2. `A.map(function (x) { return f(g(x)); })` is equivalent to `u.map(g).map(f)` (_composition_)
    1. `A.map(function (a) { return a; })` is equivalent to `A` ( _identity_ )
    2. `A.map(function (x) { return f(g(x)); })` is equivalent to `u.map(g).map(f)` ( _composition_ )

    A practical example of how `map` might be implemented is the array, which calls map for each element in the array and returns a new array that is an array of the results of the function, e.g.:

    @@ -62,22 +62,22 @@ var res = arr.map(square);

    `res` would then be `[1, 4, 9, 16]`

    (_an entity that implements `map` is also known as a 'functor' in functional programming_)
    ( _an entity that implements `map` is also known as a 'functor' in functional programming_ )

    ### A.chain(fn)

    If an entity (call it `A`) implements a method `chain` then when it is passed one argument that is a function and that function returns an entity of the same class as `A`, chain must return an entity of the same class as `A`.

    It must also obey the rule:

    1. `A.chain(f).chain(g)` is equivalent to `A.chain(function (x) { return f(x).chain(g); })` (_associativity_)
    1. `A.chain(f).chain(g)` is equivalent to `A.chain(function (x) { return f(x).chain(g); })` ( _associativity_ )

    ### A.constructor.of(B)

    Any entity that implements `of` must also implement `chain`. `A.constructor.of(B)` must return an entity of the same class as `A` which obeys the following three rules.

    1. If `f` is a function that returns an entity of class `A`, then `A.of(b).chain(f)` is equivalent to `f(b)` (_left identity_)
    1. If `f` is a function that returns an entity of class `A`, then `A.of(b).chain(f)` is equivalent to `f(b)` ( _left identity_ )
    2. `A.chain(A.constructor.of)` is equivalent to `A` (_right identity_)
    3. Nothing about the contents of `A` may be checked, it is to be treated as an opaque value

    (_an entity that implements `of` is also known as a 'monad' in functional programming_)
    ( _an entity that implements `of` is also known as a 'monad' in functional programming_ )
  5. ForbesLindesay revised this gist Apr 16, 2013. 1 changed file with 18 additions and 9 deletions.
    27 changes: 18 additions & 9 deletions Real World Specification.md
    Original file line number Diff line number Diff line change
    @@ -28,23 +28,27 @@ Examples:
    If an entity (call it `A`) implements a method `concat` then when it is passed one argument that is of the same class as `A` it must:

    1. return a value with the same type as `A` (the object on which the method was called).
    2. It must be associative. That is to say `a.concat(b).concat(c)` must be equivalent to `a.concat(b.concat(c))`
    2. It must be associative. That is to say `a.concat(b).concat(c)` must be equivalent to `a.concat(b.concat(c))` (_associativity_)

    (_an entity that implements `concat` is also known as a 'semigroup' in functional programming_)

    ### A.constructor.zero()

    Any entity that implements `zero` must also implement `concat`. `A.constructor.zero()` must return an entity of the same class as `A` which obeys the following two rules.

    1. `A` is equivalent to `A.concat(A.constructor.zero())`
    2. `A` is equivalent to `A.constructor.zero().concat(A)`
    1. `A` is equivalent to `A.concat(A.constructor.zero())` (_right identity_)
    2. `A` is equivalent to `A.constructor.zero().concat(A)` (_left identity_)

    (_an entity that implements `zero` is also known as a 'monoid' in functional programming_)

    ### A.map(fn)

    If an entity (call it `A`) implements a method `map` then when it is passed one argument that is a function, map must return an entity of the same class as `A`.

    `map` must also obey the following two rules:

    1. `A.map(function (a) { return a; })` is equivalent to `A`
    2. `A.map(function (x) { return f(g(x)); })` is equivalent to `u.map(g).map(f)`
    1. `A.map(function (a) { return a; })` is equivalent to `A` (_identity_)
    2. `A.map(function (x) { return f(g(x)); })` is equivalent to `u.map(g).map(f)` (_composition_)

    A practical example of how `map` might be implemented is the array, which calls map for each element in the array and returns a new array that is an array of the results of the function, e.g.:

    @@ -58,17 +62,22 @@ var res = arr.map(square);

    `res` would then be `[1, 4, 9, 16]`

    (_an entity that implements `map` is also known as a 'functor' in functional programming_)

    ### A.chain(fn)

    If an entity (call it `A`) implements a method `chain` then when it is passed one argument that is a function and that function returns an entity of the same class as `A`, chain must return an entity of the same class as `A`.

    It must also obey the rule:

    1. `A.chain(f).chain(g)` is equivalent to `A.chain(function (x) { return f(x).chain(g); })`
    1. `A.chain(f).chain(g)` is equivalent to `A.chain(function (x) { return f(x).chain(g); })` (_associativity_)

    ### A.constructor.of(B)

    Any entity that implements `of` must also implement `chain`. `A.constructor.of(B)` must return an entity of the same class as `A` which obeys the following two rules.
    Any entity that implements `of` must also implement `chain`. `A.constructor.of(B)` must return an entity of the same class as `A` which obeys the following three rules.

    1. If `f` is a function that returns an entity of class `A`, then `A.of(b).chain(f)` is equivalent to `f(b)` (_left identity_)
    2. `A.chain(A.constructor.of)` is equivalent to `A` (_right identity_)
    3. Nothing about the contents of `A` may be checked, it is to be treated as an opaque value

    1. If `f` is a function that returns an entity of class `A`, then `A.of(b).chain(f)` is equivalent to `f(b)`
    2. `A.chain(A.constructor.of)` is equivalent to `A`
    (_an entity that implements `of` is also known as a 'monad' in functional programming_)
  6. ForbesLindesay revised this gist Apr 16, 2013. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion Real World Specification.md
    Original file line number Diff line number Diff line change
    @@ -6,7 +6,7 @@ This project specifies the behavior of a number of methods that may optionally b

    ## Definitions

    For the purposes of this, spec, an "entity" is a method that has an `[[equivalent]]` operation (see bellow) and may implement some or all of the other methods.
    For the purposes of this, spec, an "entity" is an object that has an `[[equivalent]]` operation (see bellow) and may implement some or all of the other methods.

    A "value" is any JavaScript value, this includes entities.

  7. ForbesLindesay revised this gist Apr 16, 2013. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion Real World Specification.md
    Original file line number Diff line number Diff line change
    @@ -2,7 +2,7 @@

    (aka "Algebraic JavaScript Specification")

    This project specifies the behavior of a number of methods that may optionally be added to any object. The motivation behind this is to encourage greater code use. You can create functions that just rely on objects having implementations of the methods below, and in doing so you can make them work with a wide variety of different, but related data structures.
    This project specifies the behavior of a number of methods that may optionally be added to any object. The motivation behind this is to encourage greater code reuse. You can create functions that just rely on objects having implementations of the methods below, and in doing so you can make them work with a wide variety of different, but related data structures.

    ## Definitions

  8. ForbesLindesay revised this gist Apr 16, 2013. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion Real World Specification.md
    Original file line number Diff line number Diff line change
    @@ -66,7 +66,7 @@ It must also obey the rule:

    1. `A.chain(f).chain(g)` is equivalent to `A.chain(function (x) { return f(x).chain(g); })`

    ### `A.constructor.of(B)`
    ### A.constructor.of(B)

    Any entity that implements `of` must also implement `chain`. `A.constructor.of(B)` must return an entity of the same class as `A` which obeys the following two rules.

  9. ForbesLindesay revised this gist Apr 16, 2013. 1 changed file with 9 additions and 9 deletions.
    18 changes: 9 additions & 9 deletions Real World Specification.md
    Original file line number Diff line number Diff line change
    @@ -27,24 +27,24 @@ Examples:

    If an entity (call it `A`) implements a method `concat` then when it is passed one argument that is of the same class as `A` it must:

    1. return a value with the same type as `A` (the object on which the method was called).
    2. It must be associative. That is to say `a.concat(b).concat(c)` must be equivalent to `a.concat(b.concat(c))`
    1. return a value with the same type as `A` (the object on which the method was called).
    2. It must be associative. That is to say `a.concat(b).concat(c)` must be equivalent to `a.concat(b.concat(c))`

    ### A.constructor.zero()

    Any entity that implements `zero` must also implement `concat`. `A.constructor.zero()` must return an entity of the same class as `A` which obeys the following two rules.

    `A` is equivalent to `A.concat(A.constructor.zero())`
    `A` is equivalent to `A.constructor.zero().concat(A)`
    1. `A` is equivalent to `A.concat(A.constructor.zero())`
    2. `A` is equivalent to `A.constructor.zero().concat(A)`

    ### A.map(fn)

    If an entity (call it `A`) implements a method `map` then when it is passed one argument that is a function, map must return an entity of the same class as `A`.

    `map` must also obey the following two rules:

    `A.map(function (a) { return a; })` is equivalent to `A`
    `A.map(function (x) { return f(g(x)); })` is equivalent to `u.map(g).map(f)`
    1. `A.map(function (a) { return a; })` is equivalent to `A`
    2. `A.map(function (x) { return f(g(x)); })` is equivalent to `u.map(g).map(f)`

    A practical example of how `map` might be implemented is the array, which calls map for each element in the array and returns a new array that is an array of the results of the function, e.g.:

    @@ -64,11 +64,11 @@ If an entity (call it `A`) implements a method `chain` then when it is passed on

    It must also obey the rule:

    `A.chain(f).chain(g)` is equivalent to `A.chain(function (x) { return f(x).chain(g); })`
    1. `A.chain(f).chain(g)` is equivalent to `A.chain(function (x) { return f(x).chain(g); })`

    ### `A.constructor.of(B)`

    Any entity that implements `of` must also implement `chain`. `A.constructor.of(B)` must return an entity of the same class as `A` which obeys the following two rules.

    If `f` is a function that returns an entity of class `A`, then `A.of(b).chain(f)` is equivalent to `f(b)`
    `A.chain(A.constructor.of)` is equivalent to `A`
    1. If `f` is a function that returns an entity of class `A`, then `A.of(b).chain(f)` is equivalent to `f(b)`
    2. `A.chain(A.constructor.of)` is equivalent to `A`
  10. ForbesLindesay revised this gist Apr 16, 2013. 1 changed file with 15 additions and 9 deletions.
    24 changes: 15 additions & 9 deletions Real World Specification.md
    Original file line number Diff line number Diff line change
    @@ -6,33 +6,38 @@ This project specifies the behavior of a number of methods that may optionally b

    ## Definitions

    For the purposes of this, spec, an "entity" is a method that implements `.equivalence` and may implement some or all of the other methods.
    For the purposes of this, spec, an "entity" is a method that has an `[[equivalent]]` operation (see bellow) and may implement some or all of the other methods.

    A "value" is any JavaScript value, this includes entities.

    ## Methods
    ## [[equivalent]]

    [[equivalent]] is an imaginary function that takes two arguments and returns `true` or `false`. It should return `true` iff the two objects could be swapped and no program would be able to tell the difference other than by checking the exact object references.

    ### `A.equivalent(B)`
    Examples:

    All entities must implement equivallence. It must return `true` or `false` when given an entity of the same class.
    - Two numbers are equivalent if they are equal
    - Two strings are equivalent if they are equal
    - Two arrays are equivalent if they contain equivalent items in the same order
    - Two functions (that have no side effects) are equivalent if they return equivalent outputs for equivalent inputs.

    e.g. numbers would be equivalent if they are equal. Arrays would be equivalent if they are of the same length and contain equivalent elements in the same order.
    ## Methods

    ### `A.concat(B)`
    ### A.concat(B)

    If an entity (call it `A`) implements a method `concat` then when it is passed one argument that is of the same class as `A` it must:

    1. return a value with the same type as `A` (the object on which the method was called).
    2. It must be associative. That is to say `a.concat(b).concat(c)` must be equivalent to `a.concat(b.concat(c))`

    ### `A.constructor.zero()`
    ### A.constructor.zero()

    Any entity that implements `zero` must also implement `concat`. `A.constructor.zero()` must return an entity of the same class as `A` which obeys the following two rules.

    `A` is equivalent to `A.concat(A.constructor.zero())`
    `A` is equivalent to `A.constructor.zero().concat(A)`

    ### `A.map(fn)`
    ### A.map(fn)

    If an entity (call it `A`) implements a method `map` then when it is passed one argument that is a function, map must return an entity of the same class as `A`.

    @@ -49,9 +54,10 @@ function square(a) {
    return a * a;
    }
    var res = arr.map(square);
    assert(res.equivalent([1, 3, 9, 16]));
    ```

    `res` would then be `[1, 4, 9, 16]`

    ### A.chain(fn)

    If an entity (call it `A`) implements a method `chain` then when it is passed one argument that is a function and that function returns an entity of the same class as `A`, chain must return an entity of the same class as `A`.
  11. ForbesLindesay created this gist Apr 16, 2013.
    68 changes: 68 additions & 0 deletions Real World Specification.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,68 @@
    # Real World Specification

    (aka "Algebraic JavaScript Specification")

    This project specifies the behavior of a number of methods that may optionally be added to any object. The motivation behind this is to encourage greater code use. You can create functions that just rely on objects having implementations of the methods below, and in doing so you can make them work with a wide variety of different, but related data structures.

    ## Definitions

    For the purposes of this, spec, an "entity" is a method that implements `.equivalence` and may implement some or all of the other methods.

    A "value" is any JavaScript value, this includes entities.

    ## Methods

    ### `A.equivalent(B)`

    All entities must implement equivallence. It must return `true` or `false` when given an entity of the same class.

    e.g. numbers would be equivalent if they are equal. Arrays would be equivalent if they are of the same length and contain equivalent elements in the same order.

    ### `A.concat(B)`

    If an entity (call it `A`) implements a method `concat` then when it is passed one argument that is of the same class as `A` it must:

    1. return a value with the same type as `A` (the object on which the method was called).
    2. It must be associative. That is to say `a.concat(b).concat(c)` must be equivalent to `a.concat(b.concat(c))`

    ### `A.constructor.zero()`

    Any entity that implements `zero` must also implement `concat`. `A.constructor.zero()` must return an entity of the same class as `A` which obeys the following two rules.

    `A` is equivalent to `A.concat(A.constructor.zero())`
    `A` is equivalent to `A.constructor.zero().concat(A)`

    ### `A.map(fn)`

    If an entity (call it `A`) implements a method `map` then when it is passed one argument that is a function, map must return an entity of the same class as `A`.

    `map` must also obey the following two rules:

    `A.map(function (a) { return a; })` is equivalent to `A`
    `A.map(function (x) { return f(g(x)); })` is equivalent to `u.map(g).map(f)`

    A practical example of how `map` might be implemented is the array, which calls map for each element in the array and returns a new array that is an array of the results of the function, e.g.:

    ```js
    var arr = [1, 2, 3, 4];
    function square(a) {
    return a * a;
    }
    var res = arr.map(square);
    assert(res.equivalent([1, 3, 9, 16]));
    ```

    ### A.chain(fn)

    If an entity (call it `A`) implements a method `chain` then when it is passed one argument that is a function and that function returns an entity of the same class as `A`, chain must return an entity of the same class as `A`.

    It must also obey the rule:

    `A.chain(f).chain(g)` is equivalent to `A.chain(function (x) { return f(x).chain(g); })`

    ### `A.constructor.of(B)`

    Any entity that implements `of` must also implement `chain`. `A.constructor.of(B)` must return an entity of the same class as `A` which obeys the following two rules.

    If `f` is a function that returns an entity of class `A`, then `A.of(b).chain(f)` is equivalent to `f(b)`
    `A.chain(A.constructor.of)` is equivalent to `A`