This is an example of use of the new approach for fantasy-land proposed in fantasyland/fantasy-land#199
Read this commnet to understand what "Spec compatible Type Representative" and "spec compatible value" means.
This is an example of use of the new approach for fantasy-land proposed in fantasyland/fantasy-land#199
Read this commnet to understand what "Spec compatible Type Representative" and "spec compatible value" means.
| // This module exposes Representative that produces spec compatible values. | |
| const Maybe = { | |
| of(x) { | |
| return { | |
| 'fantasy-land': Maybe, | |
| type: 'just', | |
| value: x, | |
| } | |
| }, | |
| nothing: { | |
| 'fantasy-land': Maybe, | |
| type: 'nothing', | |
| }, | |
| map(f, v) { | |
| return v.type === 'nothing' ? v : Maybe.of(f(v.value)) | |
| }, | |
| ap(f, v) { | |
| return f.type === 'nothing' ? f : (v.type === 'nothing' ? v : Maybe.of(f.value(v.value))) | |
| }, | |
| } | |
| export {Maybe} |
| // This module also exposes Representative that produces spec compatible values | |
| // but uses JavaScript classes under the hood. | |
| function IdC(x) { | |
| this._x = x | |
| } | |
| const Id = { | |
| of(x) { | |
| return new IdC(x) | |
| }, | |
| map(f, v) { | |
| return new IdC(f(v._x)) | |
| }, | |
| ap(f, v) { | |
| return new IdC(f._x(v._x)) | |
| } | |
| } | |
| IdC.prototype['fantasy-land'] = Id | |
| export {Id} |
| // Unlike in maybe.js and id.js in this module we expose Representatives | |
| // that produce spec _incompatible_ values but Representatives themselves are compatible. | |
| const List = { | |
| of(x) {return [x]}, | |
| map(f, v) {return v.map(f)}, | |
| ap(f, v) {return f.map(f => v.map(f)).reduce((r, i) => r.concat(i), [])}, | |
| } | |
| const ZipList = { | |
| of(x) {return [x]}, | |
| map(f, v) {return v.map(f)}, | |
| ap(f, v) {return f.map((f, i) => f(v[i]))}, | |
| } | |
| export {List, ZipList} |
| // In this module we write code that works with spec compatible values. | |
| // We don't have to pass Representatives around, but all values must have `fantasy-land` property. | |
| import {Id} from 'id' | |
| import {Maybe} from 'maybe' | |
| // Generic code | |
| function lift2(f, a, b) { | |
| const T = a['fnatasy-land'] | |
| return T.ap(T.map(a => b => f(a, b), a), b) | |
| } | |
| // App code | |
| lift2((a, b) => a + b, Id.of(1), Id.of(2)) // Id.of(3) | |
| lift2((a, b) => a + b, Maybe.of(1), Maybe.nothing) // Maybe.nothing |
| // In this module we write code that works with spec compatible Type Representatives. | |
| // We can use array.js here as well as maybe.js and id.js. | |
| import {List, ZipList} from 'array' | |
| import {Maybe} from 'maybe' | |
| // Generic code | |
| function lift2(T, f, a, b) { | |
| return T.ap(T.map(a => b => f(a, b), a), b) | |
| } | |
| // App code | |
| lift2(Id, (a, b) => a + b, Id.of(1), Id.of(2)) // Id.of(3) | |
| lift2(List, (a, b) => a + b, [1, 2], [3, 4]) // [3, 5, 5, 6] | |
| lift2(ZipList, (a, b) => a + b, [1, 2], [3, 4]) // [3, 6] |