From b139ed37afce636b97450f13b2e9936908c93b3a Mon Sep 17 00:00:00 2001 From: Ian Hofmann-Hicks Date: Sun, 31 Dec 2017 17:33:24 -0800 Subject: [PATCH] Add State Docs (#171) * add State README * update typos and PR feedback --- .travis.yml | 1 + docs/package-lock.json | 905 --------------------------------------- package-lock.json | 912 ---------------------------------------- src/State/README.md | 673 +++++++++++++++++++++++++++++ src/State/State.spec.js | 1 - 5 files changed, 674 insertions(+), 1818 deletions(-) create mode 100644 src/State/README.md diff --git a/.travis.yml b/.travis.yml index 4686a619d..3c146c7f3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,7 @@ language: node_js node_js: + - '8' - '7' - '6' - '5' diff --git a/docs/package-lock.json b/docs/package-lock.json index 4cf80b7c8..296b4714e 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -2003,7 +2003,6 @@ "requires": { "anymatch": "1.3.2", "async-each": "1.0.1", - "fsevents": "1.1.3", "glob-parent": "2.0.0", "inherits": "2.0.3", "is-binary-path": "1.0.1", @@ -4241,910 +4240,6 @@ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, - "fsevents": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.1.3.tgz", - "integrity": "sha512-WIr7iDkdmdbxu/Gh6eKEZJL6KPE74/5MEsf2whTOFNxbIoIixogroLdKYqB6FDav4Wavh/lZdzzd3b2KxIXC5Q==", - "dev": true, - "optional": true, - "requires": { - "nan": "2.8.0", - "node-pre-gyp": "0.6.39" - }, - "dependencies": { - "abbrev": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "optional": true - }, - "ajv": { - "version": "4.11.8", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "co": "4.6.0", - "json-stable-stringify": "1.0.1" - } - }, - "ansi-regex": { - "version": "2.1.1", - "bundled": true, - "dev": true - }, - "aproba": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "are-we-there-yet": { - "version": "1.1.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "delegates": "1.0.0", - "readable-stream": "2.2.9" - } - }, - "asn1": { - "version": "0.2.3", - "bundled": true, - "dev": true, - "optional": true - }, - "assert-plus": { - "version": "0.2.0", - "bundled": true, - "dev": true, - "optional": true - }, - "asynckit": { - "version": "0.4.0", - "bundled": true, - "dev": true, - "optional": true - }, - "aws-sign2": { - "version": "0.6.0", - "bundled": true, - "dev": true, - "optional": true - }, - "aws4": { - "version": "1.6.0", - "bundled": true, - "dev": true, - "optional": true - }, - "balanced-match": { - "version": "0.4.2", - "bundled": true, - "dev": true - }, - "bcrypt-pbkdf": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "tweetnacl": "0.14.5" - } - }, - "block-stream": { - "version": "0.0.9", - "bundled": true, - "dev": true, - "requires": { - "inherits": "2.0.3" - } - }, - "boom": { - "version": "2.10.1", - "bundled": true, - "dev": true, - "requires": { - "hoek": "2.16.3" - } - }, - "brace-expansion": { - "version": "1.1.7", - "bundled": true, - "dev": true, - "requires": { - "balanced-match": "0.4.2", - "concat-map": "0.0.1" - } - }, - "buffer-shims": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "caseless": { - "version": "0.12.0", - "bundled": true, - "dev": true, - "optional": true - }, - "co": { - "version": "4.6.0", - "bundled": true, - "dev": true, - "optional": true - }, - "code-point-at": { - "version": "1.1.0", - "bundled": true, - "dev": true - }, - "combined-stream": { - "version": "1.0.5", - "bundled": true, - "dev": true, - "requires": { - "delayed-stream": "1.0.0" - } - }, - "concat-map": { - "version": "0.0.1", - "bundled": true, - "dev": true - }, - "console-control-strings": { - "version": "1.1.0", - "bundled": true, - "dev": true - }, - "core-util-is": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "cryptiles": { - "version": "2.0.5", - "bundled": true, - "dev": true, - "requires": { - "boom": "2.10.1" - } - }, - "dashdash": { - "version": "1.14.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "assert-plus": "1.0.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "debug": { - "version": "2.6.8", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ms": "2.0.0" - } - }, - "deep-extend": { - "version": "0.4.2", - "bundled": true, - "dev": true, - "optional": true - }, - "delayed-stream": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "delegates": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "detect-libc": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "ecc-jsbn": { - "version": "0.1.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "jsbn": "0.1.1" - } - }, - "extend": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "extsprintf": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "forever-agent": { - "version": "0.6.1", - "bundled": true, - "dev": true, - "optional": true - }, - "form-data": { - "version": "2.1.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "asynckit": "0.4.0", - "combined-stream": "1.0.5", - "mime-types": "2.1.15" - } - }, - "fs.realpath": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "fstream": { - "version": "1.0.11", - "bundled": true, - "dev": true, - "requires": { - "graceful-fs": "4.1.11", - "inherits": "2.0.3", - "mkdirp": "0.5.1", - "rimraf": "2.6.1" - } - }, - "fstream-ignore": { - "version": "1.0.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "fstream": "1.0.11", - "inherits": "2.0.3", - "minimatch": "3.0.4" - } - }, - "gauge": { - "version": "2.7.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "aproba": "1.1.1", - "console-control-strings": "1.1.0", - "has-unicode": "2.0.1", - "object-assign": "4.1.1", - "signal-exit": "3.0.2", - "string-width": "1.0.2", - "strip-ansi": "3.0.1", - "wide-align": "1.1.2" - } - }, - "getpass": { - "version": "0.1.7", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "assert-plus": "1.0.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "glob": { - "version": "7.1.2", - "bundled": true, - "dev": true, - "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" - } - }, - "graceful-fs": { - "version": "4.1.11", - "bundled": true, - "dev": true - }, - "har-schema": { - "version": "1.0.5", - "bundled": true, - "dev": true, - "optional": true - }, - "har-validator": { - "version": "4.2.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ajv": "4.11.8", - "har-schema": "1.0.5" - } - }, - "has-unicode": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "hawk": { - "version": "3.1.3", - "bundled": true, - "dev": true, - "requires": { - "boom": "2.10.1", - "cryptiles": "2.0.5", - "hoek": "2.16.3", - "sntp": "1.0.9" - } - }, - "hoek": { - "version": "2.16.3", - "bundled": true, - "dev": true - }, - "http-signature": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "assert-plus": "0.2.0", - "jsprim": "1.4.0", - "sshpk": "1.13.0" - } - }, - "inflight": { - "version": "1.0.6", - "bundled": true, - "dev": true, - "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" - } - }, - "inherits": { - "version": "2.0.3", - "bundled": true, - "dev": true - }, - "ini": { - "version": "1.3.4", - "bundled": true, - "dev": true, - "optional": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "number-is-nan": "1.0.1" - } - }, - "is-typedarray": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "isarray": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "isstream": { - "version": "0.1.2", - "bundled": true, - "dev": true, - "optional": true - }, - "jodid25519": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "jsbn": "0.1.1" - } - }, - "jsbn": { - "version": "0.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "json-schema": { - "version": "0.2.3", - "bundled": true, - "dev": true, - "optional": true - }, - "json-stable-stringify": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "jsonify": "0.0.0" - } - }, - "json-stringify-safe": { - "version": "5.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "jsonify": { - "version": "0.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "jsprim": { - "version": "1.4.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.0.2", - "json-schema": "0.2.3", - "verror": "1.3.6" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "mime-db": { - "version": "1.27.0", - "bundled": true, - "dev": true - }, - "mime-types": { - "version": "2.1.15", - "bundled": true, - "dev": true, - "requires": { - "mime-db": "1.27.0" - } - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "dev": true, - "requires": { - "brace-expansion": "1.1.7" - } - }, - "minimist": { - "version": "0.0.8", - "bundled": true, - "dev": true - }, - "mkdirp": { - "version": "0.5.1", - "bundled": true, - "dev": true, - "requires": { - "minimist": "0.0.8" - } - }, - "ms": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "node-pre-gyp": { - "version": "0.6.39", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "detect-libc": "1.0.2", - "hawk": "3.1.3", - "mkdirp": "0.5.1", - "nopt": "4.0.1", - "npmlog": "4.1.0", - "rc": "1.2.1", - "request": "2.81.0", - "rimraf": "2.6.1", - "semver": "5.3.0", - "tar": "2.2.1", - "tar-pack": "3.4.0" - } - }, - "nopt": { - "version": "4.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "abbrev": "1.1.0", - "osenv": "0.1.4" - } - }, - "npmlog": { - "version": "4.1.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "are-we-there-yet": "1.1.4", - "console-control-strings": "1.1.0", - "gauge": "2.7.4", - "set-blocking": "2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "oauth-sign": { - "version": "0.8.2", - "bundled": true, - "dev": true, - "optional": true - }, - "object-assign": { - "version": "4.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "once": { - "version": "1.4.0", - "bundled": true, - "dev": true, - "requires": { - "wrappy": "1.0.2" - } - }, - "os-homedir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "os-tmpdir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "osenv": { - "version": "0.1.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "os-homedir": "1.0.2", - "os-tmpdir": "1.0.2" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "performance-now": { - "version": "0.2.0", - "bundled": true, - "dev": true, - "optional": true - }, - "process-nextick-args": { - "version": "1.0.7", - "bundled": true, - "dev": true - }, - "punycode": { - "version": "1.4.1", - "bundled": true, - "dev": true, - "optional": true - }, - "qs": { - "version": "6.4.0", - "bundled": true, - "dev": true, - "optional": true - }, - "rc": { - "version": "1.2.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "deep-extend": "0.4.2", - "ini": "1.3.4", - "minimist": "1.2.0", - "strip-json-comments": "2.0.1" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "readable-stream": { - "version": "2.2.9", - "bundled": true, - "dev": true, - "requires": { - "buffer-shims": "1.0.0", - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "1.0.7", - "string_decoder": "1.0.1", - "util-deprecate": "1.0.2" - } - }, - "request": { - "version": "2.81.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "aws-sign2": "0.6.0", - "aws4": "1.6.0", - "caseless": "0.12.0", - "combined-stream": "1.0.5", - "extend": "3.0.1", - "forever-agent": "0.6.1", - "form-data": "2.1.4", - "har-validator": "4.2.1", - "hawk": "3.1.3", - "http-signature": "1.1.1", - "is-typedarray": "1.0.0", - "isstream": "0.1.2", - "json-stringify-safe": "5.0.1", - "mime-types": "2.1.15", - "oauth-sign": "0.8.2", - "performance-now": "0.2.0", - "qs": "6.4.0", - "safe-buffer": "5.0.1", - "stringstream": "0.0.5", - "tough-cookie": "2.3.2", - "tunnel-agent": "0.6.0", - "uuid": "3.0.1" - } - }, - "rimraf": { - "version": "2.6.1", - "bundled": true, - "dev": true, - "requires": { - "glob": "7.1.2" - } - }, - "safe-buffer": { - "version": "5.0.1", - "bundled": true, - "dev": true - }, - "semver": { - "version": "5.3.0", - "bundled": true, - "dev": true, - "optional": true - }, - "set-blocking": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "sntp": { - "version": "1.0.9", - "bundled": true, - "dev": true, - "requires": { - "hoek": "2.16.3" - } - }, - "sshpk": { - "version": "1.13.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "asn1": "0.2.3", - "assert-plus": "1.0.0", - "bcrypt-pbkdf": "1.0.1", - "dashdash": "1.14.1", - "ecc-jsbn": "0.1.1", - "getpass": "0.1.7", - "jodid25519": "1.0.2", - "jsbn": "0.1.1", - "tweetnacl": "0.14.5" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "string-width": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" - } - }, - "string_decoder": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "requires": { - "safe-buffer": "5.0.1" - } - }, - "stringstream": { - "version": "0.0.5", - "bundled": true, - "dev": true, - "optional": true - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "requires": { - "ansi-regex": "2.1.1" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "tar": { - "version": "2.2.1", - "bundled": true, - "dev": true, - "requires": { - "block-stream": "0.0.9", - "fstream": "1.0.11", - "inherits": "2.0.3" - } - }, - "tar-pack": { - "version": "3.4.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "debug": "2.6.8", - "fstream": "1.0.11", - "fstream-ignore": "1.0.5", - "once": "1.4.0", - "readable-stream": "2.2.9", - "rimraf": "2.6.1", - "tar": "2.2.1", - "uid-number": "0.0.6" - } - }, - "tough-cookie": { - "version": "2.3.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "punycode": "1.4.1" - } - }, - "tunnel-agent": { - "version": "0.6.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safe-buffer": "5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "bundled": true, - "dev": true, - "optional": true - }, - "uid-number": { - "version": "0.0.6", - "bundled": true, - "dev": true, - "optional": true - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "uuid": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "verror": { - "version": "1.3.6", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "extsprintf": "1.0.2" - } - }, - "wide-align": { - "version": "1.1.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "string-width": "1.0.2" - } - }, - "wrappy": { - "version": "1.0.2", - "bundled": true, - "dev": true - } - } - }, "fstream": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz", diff --git a/package-lock.json b/package-lock.json index 309f5b2b5..f5e5cf2b9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -589,7 +589,6 @@ "requires": { "anymatch": "1.3.2", "async-each": "1.0.1", - "fsevents": "1.1.3", "glob-parent": "2.0.0", "inherits": "2.0.3", "is-binary-path": "1.0.1", @@ -1568,910 +1567,6 @@ "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, - "fsevents": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.1.3.tgz", - "integrity": "sha512-WIr7iDkdmdbxu/Gh6eKEZJL6KPE74/5MEsf2whTOFNxbIoIixogroLdKYqB6FDav4Wavh/lZdzzd3b2KxIXC5Q==", - "dev": true, - "optional": true, - "requires": { - "nan": "2.8.0", - "node-pre-gyp": "0.6.39" - }, - "dependencies": { - "abbrev": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "optional": true - }, - "ajv": { - "version": "4.11.8", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "co": "4.6.0", - "json-stable-stringify": "1.0.1" - } - }, - "ansi-regex": { - "version": "2.1.1", - "bundled": true, - "dev": true - }, - "aproba": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "are-we-there-yet": { - "version": "1.1.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "delegates": "1.0.0", - "readable-stream": "2.2.9" - } - }, - "asn1": { - "version": "0.2.3", - "bundled": true, - "dev": true, - "optional": true - }, - "assert-plus": { - "version": "0.2.0", - "bundled": true, - "dev": true, - "optional": true - }, - "asynckit": { - "version": "0.4.0", - "bundled": true, - "dev": true, - "optional": true - }, - "aws-sign2": { - "version": "0.6.0", - "bundled": true, - "dev": true, - "optional": true - }, - "aws4": { - "version": "1.6.0", - "bundled": true, - "dev": true, - "optional": true - }, - "balanced-match": { - "version": "0.4.2", - "bundled": true, - "dev": true - }, - "bcrypt-pbkdf": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "tweetnacl": "0.14.5" - } - }, - "block-stream": { - "version": "0.0.9", - "bundled": true, - "dev": true, - "requires": { - "inherits": "2.0.3" - } - }, - "boom": { - "version": "2.10.1", - "bundled": true, - "dev": true, - "requires": { - "hoek": "2.16.3" - } - }, - "brace-expansion": { - "version": "1.1.7", - "bundled": true, - "dev": true, - "requires": { - "balanced-match": "0.4.2", - "concat-map": "0.0.1" - } - }, - "buffer-shims": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "caseless": { - "version": "0.12.0", - "bundled": true, - "dev": true, - "optional": true - }, - "co": { - "version": "4.6.0", - "bundled": true, - "dev": true, - "optional": true - }, - "code-point-at": { - "version": "1.1.0", - "bundled": true, - "dev": true - }, - "combined-stream": { - "version": "1.0.5", - "bundled": true, - "dev": true, - "requires": { - "delayed-stream": "1.0.0" - } - }, - "concat-map": { - "version": "0.0.1", - "bundled": true, - "dev": true - }, - "console-control-strings": { - "version": "1.1.0", - "bundled": true, - "dev": true - }, - "core-util-is": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "cryptiles": { - "version": "2.0.5", - "bundled": true, - "dev": true, - "requires": { - "boom": "2.10.1" - } - }, - "dashdash": { - "version": "1.14.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "assert-plus": "1.0.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "debug": { - "version": "2.6.8", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ms": "2.0.0" - } - }, - "deep-extend": { - "version": "0.4.2", - "bundled": true, - "dev": true, - "optional": true - }, - "delayed-stream": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "delegates": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "detect-libc": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "ecc-jsbn": { - "version": "0.1.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "jsbn": "0.1.1" - } - }, - "extend": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "extsprintf": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "forever-agent": { - "version": "0.6.1", - "bundled": true, - "dev": true, - "optional": true - }, - "form-data": { - "version": "2.1.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "asynckit": "0.4.0", - "combined-stream": "1.0.5", - "mime-types": "2.1.15" - } - }, - "fs.realpath": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "fstream": { - "version": "1.0.11", - "bundled": true, - "dev": true, - "requires": { - "graceful-fs": "4.1.11", - "inherits": "2.0.3", - "mkdirp": "0.5.1", - "rimraf": "2.6.1" - } - }, - "fstream-ignore": { - "version": "1.0.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "fstream": "1.0.11", - "inherits": "2.0.3", - "minimatch": "3.0.4" - } - }, - "gauge": { - "version": "2.7.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "aproba": "1.1.1", - "console-control-strings": "1.1.0", - "has-unicode": "2.0.1", - "object-assign": "4.1.1", - "signal-exit": "3.0.2", - "string-width": "1.0.2", - "strip-ansi": "3.0.1", - "wide-align": "1.1.2" - } - }, - "getpass": { - "version": "0.1.7", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "assert-plus": "1.0.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "glob": { - "version": "7.1.2", - "bundled": true, - "dev": true, - "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" - } - }, - "graceful-fs": { - "version": "4.1.11", - "bundled": true, - "dev": true - }, - "har-schema": { - "version": "1.0.5", - "bundled": true, - "dev": true, - "optional": true - }, - "har-validator": { - "version": "4.2.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ajv": "4.11.8", - "har-schema": "1.0.5" - } - }, - "has-unicode": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "hawk": { - "version": "3.1.3", - "bundled": true, - "dev": true, - "requires": { - "boom": "2.10.1", - "cryptiles": "2.0.5", - "hoek": "2.16.3", - "sntp": "1.0.9" - } - }, - "hoek": { - "version": "2.16.3", - "bundled": true, - "dev": true - }, - "http-signature": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "assert-plus": "0.2.0", - "jsprim": "1.4.0", - "sshpk": "1.13.0" - } - }, - "inflight": { - "version": "1.0.6", - "bundled": true, - "dev": true, - "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" - } - }, - "inherits": { - "version": "2.0.3", - "bundled": true, - "dev": true - }, - "ini": { - "version": "1.3.4", - "bundled": true, - "dev": true, - "optional": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "requires": { - "number-is-nan": "1.0.1" - } - }, - "is-typedarray": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "isarray": { - "version": "1.0.0", - "bundled": true, - "dev": true - }, - "isstream": { - "version": "0.1.2", - "bundled": true, - "dev": true, - "optional": true - }, - "jodid25519": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "jsbn": "0.1.1" - } - }, - "jsbn": { - "version": "0.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "json-schema": { - "version": "0.2.3", - "bundled": true, - "dev": true, - "optional": true - }, - "json-stable-stringify": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "jsonify": "0.0.0" - } - }, - "json-stringify-safe": { - "version": "5.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "jsonify": { - "version": "0.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "jsprim": { - "version": "1.4.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.0.2", - "json-schema": "0.2.3", - "verror": "1.3.6" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "mime-db": { - "version": "1.27.0", - "bundled": true, - "dev": true - }, - "mime-types": { - "version": "2.1.15", - "bundled": true, - "dev": true, - "requires": { - "mime-db": "1.27.0" - } - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "dev": true, - "requires": { - "brace-expansion": "1.1.7" - } - }, - "minimist": { - "version": "0.0.8", - "bundled": true, - "dev": true - }, - "mkdirp": { - "version": "0.5.1", - "bundled": true, - "dev": true, - "requires": { - "minimist": "0.0.8" - } - }, - "ms": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "node-pre-gyp": { - "version": "0.6.39", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "detect-libc": "1.0.2", - "hawk": "3.1.3", - "mkdirp": "0.5.1", - "nopt": "4.0.1", - "npmlog": "4.1.0", - "rc": "1.2.1", - "request": "2.81.0", - "rimraf": "2.6.1", - "semver": "5.3.0", - "tar": "2.2.1", - "tar-pack": "3.4.0" - } - }, - "nopt": { - "version": "4.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "abbrev": "1.1.0", - "osenv": "0.1.4" - } - }, - "npmlog": { - "version": "4.1.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "are-we-there-yet": "1.1.4", - "console-control-strings": "1.1.0", - "gauge": "2.7.4", - "set-blocking": "2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "oauth-sign": { - "version": "0.8.2", - "bundled": true, - "dev": true, - "optional": true - }, - "object-assign": { - "version": "4.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "once": { - "version": "1.4.0", - "bundled": true, - "dev": true, - "requires": { - "wrappy": "1.0.2" - } - }, - "os-homedir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "os-tmpdir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "osenv": { - "version": "0.1.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "os-homedir": "1.0.2", - "os-tmpdir": "1.0.2" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true, - "dev": true - }, - "performance-now": { - "version": "0.2.0", - "bundled": true, - "dev": true, - "optional": true - }, - "process-nextick-args": { - "version": "1.0.7", - "bundled": true, - "dev": true - }, - "punycode": { - "version": "1.4.1", - "bundled": true, - "dev": true, - "optional": true - }, - "qs": { - "version": "6.4.0", - "bundled": true, - "dev": true, - "optional": true - }, - "rc": { - "version": "1.2.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "deep-extend": "0.4.2", - "ini": "1.3.4", - "minimist": "1.2.0", - "strip-json-comments": "2.0.1" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "readable-stream": { - "version": "2.2.9", - "bundled": true, - "dev": true, - "requires": { - "buffer-shims": "1.0.0", - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "1.0.7", - "string_decoder": "1.0.1", - "util-deprecate": "1.0.2" - } - }, - "request": { - "version": "2.81.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "aws-sign2": "0.6.0", - "aws4": "1.6.0", - "caseless": "0.12.0", - "combined-stream": "1.0.5", - "extend": "3.0.1", - "forever-agent": "0.6.1", - "form-data": "2.1.4", - "har-validator": "4.2.1", - "hawk": "3.1.3", - "http-signature": "1.1.1", - "is-typedarray": "1.0.0", - "isstream": "0.1.2", - "json-stringify-safe": "5.0.1", - "mime-types": "2.1.15", - "oauth-sign": "0.8.2", - "performance-now": "0.2.0", - "qs": "6.4.0", - "safe-buffer": "5.0.1", - "stringstream": "0.0.5", - "tough-cookie": "2.3.2", - "tunnel-agent": "0.6.0", - "uuid": "3.0.1" - } - }, - "rimraf": { - "version": "2.6.1", - "bundled": true, - "dev": true, - "requires": { - "glob": "7.1.2" - } - }, - "safe-buffer": { - "version": "5.0.1", - "bundled": true, - "dev": true - }, - "semver": { - "version": "5.3.0", - "bundled": true, - "dev": true, - "optional": true - }, - "set-blocking": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "sntp": { - "version": "1.0.9", - "bundled": true, - "dev": true, - "requires": { - "hoek": "2.16.3" - } - }, - "sshpk": { - "version": "1.13.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "asn1": "0.2.3", - "assert-plus": "1.0.0", - "bcrypt-pbkdf": "1.0.1", - "dashdash": "1.14.1", - "ecc-jsbn": "0.1.1", - "getpass": "0.1.7", - "jodid25519": "1.0.2", - "jsbn": "0.1.1", - "tweetnacl": "0.14.5" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "string-width": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" - } - }, - "string_decoder": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "requires": { - "safe-buffer": "5.0.1" - } - }, - "stringstream": { - "version": "0.0.5", - "bundled": true, - "dev": true, - "optional": true - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "requires": { - "ansi-regex": "2.1.1" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "tar": { - "version": "2.2.1", - "bundled": true, - "dev": true, - "requires": { - "block-stream": "0.0.9", - "fstream": "1.0.11", - "inherits": "2.0.3" - } - }, - "tar-pack": { - "version": "3.4.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "debug": "2.6.8", - "fstream": "1.0.11", - "fstream-ignore": "1.0.5", - "once": "1.4.0", - "readable-stream": "2.2.9", - "rimraf": "2.6.1", - "tar": "2.2.1", - "uid-number": "0.0.6" - } - }, - "tough-cookie": { - "version": "2.3.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "punycode": "1.4.1" - } - }, - "tunnel-agent": { - "version": "0.6.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safe-buffer": "5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "bundled": true, - "dev": true, - "optional": true - }, - "uid-number": { - "version": "0.0.6", - "bundled": true, - "dev": true, - "optional": true - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true, - "dev": true - }, - "uuid": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "verror": { - "version": "1.3.6", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "extsprintf": "1.0.2" - } - }, - "wide-align": { - "version": "1.1.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "string-width": "1.0.2" - } - }, - "wrappy": { - "version": "1.0.2", - "bundled": true, - "dev": true - } - } - }, "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", @@ -3489,13 +2584,6 @@ "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", "dev": true }, - "nan": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.8.0.tgz", - "integrity": "sha1-7XFfP+neArV6XmJS2QqWZ14fCFo=", - "dev": true, - "optional": true - }, "natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", diff --git a/src/State/README.md b/src/State/README.md new file mode 100644 index 000000000..4bda845bb --- /dev/null +++ b/src/State/README.md @@ -0,0 +1,673 @@ +# State +```haskell +State s a +``` +`State` is an Algebraic Data Type that abstracts away the associated state +management that comes with stateful computations.`State` is parameterized by +two types, a state `s` and a resultant `a`. The resultant portion may vary it's +type, but the state portion must be fixed to a type that is used by all related +stateful computations. + +All `State` instances wrap a function of the form `s -> Pair a s` and can be +constructed by providing a function of this form. In order to get maximum +reuse of existing functions, a few construction helpers are available on the +`State` constructor. + +`State` is lazy and is required to be run at the edge with some initial state. +Three methods are available on the instance for running the `State` with a +given initial state. [`runWith`](#runwith) will return a `Pair a s` with the +state `s` on the right and the resultant `a` on the left. + +The other two are used for extracting either the state or resultant, unwrapping +the values from the `Pair` and discarding the unwanted portion. +[`evalWith`](#evalwith) used when the resultant is wanted, while +[`execWith`](#execwith) is used to pull the state. + +```js +const State = require('crocks/State') +const { get, put } = State + +const Pair = require('crocks/Pair') +const constant = require('crocks/combinators/constant') + + +// toUpper :: String -> String +const toUpper = + x => x.toUpperCase() + +// putResultant :: String -> State String String +const putResultant = x => + put(x) + .map(constant(x)) + +// standard construction +// State String String +State(s => Pair(toUpper(s), s)) + .runWith('nice') +//=> Pair('NICE', 'nice') + +// construction helper +// State String String +get(toUpper) + .runWith('nice') +//=> Pair('NICE', 'nice') + +// combine states +get(toUpper) + .chain(putResultant) + .runWith('nice') +//=> Pair('NICE', 'NICE') + +// pull resultant only +get(toUpper) + .evalWith('nice') +//=> 'NICE' + +// pull state only +get(toUpper) + .execWith('nice') +//=> 'nice' +``` + +## Implements +`Functor`, `Apply`, `Chain`, `Applicative`, `Monad` + +## Constructor Methods + +### get +```haskell +State.get :: () -> State s s +State.get :: (s -> a) -> State s a +``` + +A construction helper that is used to access the state portion of a given +`State` instance. To make the state accessible, `get` will place the state in +the resultant portion, overwriting what was there previously. + +`get` may be called with or without a function as it's argument. When nothing is +provided for the argument, the state will be applied to the resultant as is. The +state will be mapped over any provided function that takes the same type as the +state, with the result deposited in the resultant. + +```js +const { get } = require('crocks/State') + +const chain = require('crocks/pointfree/chain') +const compose = require('crocks/helpers/compose') +const isNumber = require('crocks/predicates/isNumber') +const option = require('crocks/pointfree/option') +const prop = require('crocks/Maybe/prop') +const safe = require('crocks/Maybe/safe') + +// propOr :: (String, (b -> Boolean), a) -> Object -> c +const propOr = (key, pred, def) => + compose(option(def), chain(safe(pred)), prop(key)) + +// safeNumber :: Object -> Number +const safeNumber = + propOr('number', isNumber, 0) + +get(safeNumber) + .runWith({ number: 23 }) +//=> Pair(23, { number: 23 }) + +get(safeNumber) + .evalWith({ number: '23' }) +//=> 0 + +get() + .map(safeNumber) + .evalWith({ number: 23 }) +//=> 23 + +get() + .map(safeNumber) + .runWith({ string: '47' }) +//=> Pair(0, { string: '47'}) +``` + +### modify +```haskell +State.modify :: (s -> s) -> State s () +``` + +A construction helper that can be used to lift an endo-function that matches +the fixed type of the state portion. The lifted function will receive the state +and returns a new `State` instance with the result of the function in the state +portion. Great care should be taken to not use functions that will change the +type of the state as it may not be expected in other stateful computations and +can result in hard to track down bugs. + +```js +const { modify } = require('crocks/State') + +const mapProps = require('crocks/helpers/mapProps') + +// add :: Number -> Number -> Number +const add = + x => y => x + y + +// addState :: Number -> State Number () +const addState = x => + modify(add(x)) + +// addValue :: Number -> State Object () +const addValue = x => + modify(mapProps({ value: add(x) })) + +addState(5) + .execWith(45) +//=> 50 + +addValue(5) + .execWith({ value: 45 }) +//=> { value: 50 } + +addValue(5) + .execWith({}) +//=> {} +``` + +### put +```haskell +State.put :: s -> State s () +``` + +Used to replace the state portion of a given State instance,, `put` can be +employed anytime that the state can change without having to know about it's +previous value. If the previous value is required for a given stateful +computation, [`modify`](#modify) can be used to lift a function that represents +the change. + +As put updates the state, it is important to ensure that the state portion stays +fixed for all related functions. Changing the type of the state portion may +result in hard to debug bugs and destroys the relationship between stateful +computations. + +```js +const { put } = require('crocks/State') + +const compose = require('crocks/helpers/compose') +const isString = require('crocks/predicates/isString') +const option = require('crocks/pointfree/option') +const safe = require('crocks/Maybe/safe') + +// safeString :: a -> String +const safeString = + compose(option(''), safe(isString)) + +// reset :: () -> State String () +const reset = () => + put('') + +// update :: a -> State String () +const update = + compose(put, safeString) + +// heckYeah :: State String () +const heckYeah = + update('Oh Heck Yeah') + +heckYeah + .execWith('Gosh') +//=> 'Oh Heck Yeah' + +heckYeah + .chain(reset) + .runWith('Gosh') +// Pair((), '') +``` + +### of +```haskell +State.of :: a -> State s a +``` + +Used to "blindly" lift any Javascript value into a `State`, `of` will take the +provided value and return back a new `State` instance with the value in +the resultant. There are many uses for `of`, but mostly it is used to set the +resultant in the same way [`put`](#put) is used to replace the state. Many times +`of` is used at the start of a given stateful computation or in conjunction +with [`put`](#put) and [`modify`](#modify) to replace the `Unit` the resultant +is set to for those construction helpers. + +```js +const State = require('crocks/State') +const { get, put } = State + +// updatePop :: String -> State String String +const updatePop = x => + get().chain( + old => put(x).chain( + () => State.of(old) + ) + ) + +State.of('hotness') + .chain(updatePop) + .runWith('crusty') +//=> Pair('crusty', 'hotness') +``` + +### type +```haskell +State.type :: () -> String +``` + +`type` provides a string representation of the type name for a given type in +`crocks`. While it is used mostly internally for law validation, it can be +useful to the end user for debugging and building out custom types based on the +standard `crocks` types. While type comparisons can easily be done manually by +calling `type` on a given type, using the `isSameType` function hides much of +the boilerplate. `type` is available on both the Constructor and the Instance +for convenience. + +```js +const State = require('crocks/State') + +const Reader = require('crocks/Reader') +const identity = require('crocks/combinators/identity') +const isSameType = require('crocks/predicates/isSameType') + +State.type() //=> "State" + +isSameType(State, State.of(3)) //=> true +isSameType(State, State) //=> true +isSameType(State, Reader(identity)) //=> false +isSameType(State.of(false), Reader) //=> false +``` + +## Instance Methods + +### map +```haskell +State s a ~> (a -> b) -> State s b +``` + +While the state portion `s` of `State` must remain fixed to a type, the +resultant `a` can vary in it's type as needed. This allows complex stateful +computations to be represented with `State`. The `map` method provides a means +to lift a function into the datatype that will be applied to the resultant and +return a new instance of `State` with the result of the function as the new +resultant. + +While this is similar to the [`modify`](#modify) construction helper, which +lifts an endo-function that acts upon the state, `map` does not require an +endo-function as it can move to any type. + +Due to the composition law associated with `map`, successive `map`s can be +composed together using function composition. This will give the same results +but will only map the value once, instead of once for every mapping. + +```js +const { get } = require('crocks/State') + +const compose = require('crocks/helpers/compose') +const objOf = require('crocks/helpers/objOf') +const propOr = require('crocks/helpers/propOr') + +// add :: Number -> Number -> Number +const add = + x => y => x + y + +// getNum :: State Object Number +const getNum = + get(propOr(0, 'num')) + +getNum + .map(add(10)) + .evalWith({ num: 32 }) +//=> 42 + +getNum + .map(add(10)) + .map(objOf('result')) + .evalWith({ val: 32 }) +//=> { result: 10 } + +// comp :: Number -> Object +const comp = compose( + objOf('result'), + add(10) +) + +getNum + .map(comp) + .evalWith({ num: 32 }) +//=> { result: 42 } +``` + +### ap +```haskell +State s (a -> b) ~> State s a -> State s b +``` + +Short for apply, the `ap` method is used to apply the resultant of a given +`State` instance to a function wrapped in another instance. On a `State` +instance that wraps a function, calling `ap`, providing it another `State` +instance, will return a new `State` instance with the result of the function +in the resultant portion. + +When used with curried, polyadic functions, multiple stateful computations can +be combined using the lifted function as a means to combine each of the +instances' resultants. + +```js +const { get, modify } = require('crocks/State') + +const assoc = require('crocks/helpers/assoc') +const propOr = require('crocks/helpers/propOr') + +const data = { + tax: .084, + sub: 34.97 +} + +// add :: Number -> Number -> Number +const add = + x => y => x + y + +// multiply :: Number -> Number -> Number +const multiply = + x => y => x * y + +// round :: Number -> Number +const round = + x => Math.round(x * 100) / 100 + +// getKey :: String -> State Object Number +const getKey = key => + get(propOr(0, key)) + +// updateKey :: String -> a -> State Object () +const updateKey = key => val => + modify(assoc(key, val)) + +// addToSub :: Number -> String Object Number +const addToSub = x => + getKey('sub') + .map(add(x)) + +const calcTax = + getKey('tax') + .map(multiply) + .ap(getKey('sub')) + +// applyTax :: State Object () +const applyTax = + calcTax + .chain(addToSub) + .map(round) + .chain(updateKey('total')) + +applyTax + .execWith(data) +//=> { tax: 0.084, sub: 34.07, total: 37.91 } +``` + +### chain +```haskell +State s a ~> (a -> State s b) -> State s b +``` + +As a means to combine stateful computations, `chain` is used to sequence +state transactions that either read from or write to the state. `chain` takes +a unary function that must return a new `State` instance. `chain` returns a new +`State` instance that will apply the computation when run. + +```js +const { get, modify } = require('crocks/State') + +// add :: Number -> State Number () +const add = x => + modify(y => x + y) + +// multiply :: Number -> State Number () +const multiply = x => + modify(y => x * y) + +// double :: () -> State Number () +const double = () => + get() + .chain(add) + +// square :: () -> State Number () +const square = () => + get() + .chain(multiply) + +add(10) + .execWith(10) +//=> 20 + +add(10) + .chain(double) + .execWith(10) +//=> 40 + +add(10) + .chain(square) + .execWith(10) +//=> 400 + +add(10) + .chain(double) + .chain(square) + .execWith(10) +//=> 1600 +``` + +### runWith +```haskell +State s a ~> s -> Pair a s +``` + +`State` is a lazy datatype that requires a value for it's state portion to be +run. A given `State` instance provides a `runWith` method that accepts a value +to run the instance with. The value must be a member of the type that the +given `State` instance is fixed to in it's state portion, `s`. + +When called, `runWith` will run the state transition with the given value as the +initial state and will return the resulting `Pair` with the resultant in the +`fst` (first) and the state in the `snd` (second). + + +```js +const State = require('crocks/State') +const { get, put } = State + +const K = require('crocks/combinators/constant') + +// swap :: s -> s -> State s s +const swap = x => old => + put(x) + .chain(K(State.of(old))) + +//update :: s -> State s s +const update = x => + get() + .chain(swap(x)) + +update(45) + .runWith(100) +//=> Pair(100, 45) +``` + +### evalWith +```haskell +State s a ~> s -> a +``` + +`State` is a lazy datatype that requires a value for it's state portion to +be run. A given `State` instance provides an `evalWith` method that accepts a +value to run the instance with. The value must be a member of the type that the +given `State` instance is fixed to in it's state portion, `s`. + +When called, `evalWith` will run the state transition with the given value as +the initial state and will return the resulting resultant discarding the state +portion. + +```js +const State = require('crocks/State') +const { get } = State + +const concat = require('crocks/pointfree/concat') +const flip = require('crocks/combinators/flip') +const liftA2 = require('crocks/helpers/liftA2') +const map = require('crocks/pointfree/map') +const propOr = require('crocks/helpers/propOr') + +const name = { + first: 'Franklin', + last: 'Jennings' +} + +// getLast :: State Object String +const getFirst = + get(propOr('', 'first')) + +// getLast :: State Object String +const getLast = + get(propOr('', 'last')) + +// inner :: Functor f => f a -> f [ a ] +const inner = + map(Array.of) + +// combineNames :: State Object [ String ] +const combineNames = liftA2( + flip(concat), + inner(getFirst), + inner(getLast) +) + +combineNames + .evalWith(name) +//=> [ 'Franklin', 'Jennings' ] +``` + +### execWith +```haskell +State s a ~> s -> s +``` + +`State` is a lazy datatype that requires a value for it's state portion to +be run. A given `State` instance provides an `execWith` method that accepts a +value to run the instance with. The value must be a member of the type that the +given `State` instance is fixed to in it's state portion, `s`. + +When called, `execWith` will run the state transition with the given value as +the initial state and will return the resulting state, discarding the resultant +portion. + +```js +const { modify } = require('crocks/State') + +const compose = require('crocks/helpers/compose') +const concat = require('crocks/pointfree/concat') + +// toUpper :: String -> String +const toUpper = + x => x.toUpperCase() + +// exclaim :: String -> String +const exclaim = + concat('!!!') + +// yell :: State String () +const yell = modify( + compose(exclaim, toUpper) +) + +yell + .execWith('nice') +//=> 'NICE!!!' +``` + +Pointfree Functions +--- + +### evalWith *(pointfree)* +```haskell +evalWith :: s -> State s a -> a +``` + +The `evalWith` pointfree function can be employed to execute the +[`evalWith`](#evalwith) method on a given `State` instance. This function is +typically used at the edge of a program where all the side-effects typically +reside. + +As all this function does is return the result of applying a given initial state +to the [`evalWith`](#evalwith) method to the provided `State` instance, it will +also return the resulting resultant, throwing away the resulting state. + + +```js +const { get } = require('crocks/State') + +const evalWith = require('crocks/State/evalWith') + +const compose = require('crocks/helpers/compose') +const curry = require('crocks/helpers/curry') +const flip = require('crocks/combinators/flip') + +// addToState :: Number -> State Number Number +const addToState = + x => get(y => x + y) + +// add :: Number -> Number -> Number +const add = curry( + compose(flip(evalWith), addToState) +) + +// add10 :: Number -> Number +const add10 = + add(10) + +add10(32) +//=> 42 + +add(1295, 42) +// 1337 +``` + +### execWith *(pointfree)* +```haskell +execWith :: s -> State s a -> s +``` + +The `execWith` pointfree function can be employed to execute the +[`execWith`](#execwith) method on a given `State` instance. This function is +typically used at the edge of a program where all the side-effects typically +reside. + +As all this function does is return the result of applying a given initial state +to the [`execWith`](#execwith) method to the provided `State` instance, it will +also return the resulting state, throwing away the resulting resultant. + +```js +const State = require('crocks/State') +const { modify } = State + +const execWith = require('crocks/State/execWith') + +const curry = require('crocks/helpers/curry') +const isSameType = require('crocks/predicates/isSameType') +const mapProps = require('crocks/helpers/mapProps') +const when = require('crocks/logic/when') + +// middleware :: Object -> State Object | Object -> Object +const middleware = curry( + s => when(isSameType(State), execWith(s)) +) + +// incValue :: State Object () +const incValue = + modify(mapProps({ value: x => x + 1 })) + +middleware({ value: 10 }, incValue) +//=> { value: 11 } + +middleware({ value: 10 }, { value: 32 }) +//=> { value: 32 } +``` diff --git a/src/State/State.spec.js b/src/State/State.spec.js index d3d67aa7b..13131db1b 100644 --- a/src/State/State.spec.js +++ b/src/State/State.spec.js @@ -79,7 +79,6 @@ test('State runWith errors', t => { const runWith = bindFunc(State(identity).runWith) const err = /State.runWith: Must wrap a function in the form \(s -> Pair a s\)/ - t.throws(runWith(undefined), err, 'throws when wrapped function returns undefined') t.throws(runWith(null), err, 'throws when wrapped function returns null') t.throws(runWith(0), err, 'throws when wrapped function returns falsey number')