-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
14 changed files
with
585 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
/* eslint-disable no-unused-vars */ | ||
const OFF = 0 | ||
const WARNING = 1 | ||
const ERROR = 2 | ||
/* eslint-enable no-unused-vars */ | ||
|
||
module.exports = { | ||
parser: 'babel-eslint', | ||
|
||
extends: 'standard', | ||
|
||
rules: { | ||
'comma-dangle': [ERROR, 'always-multiline'], | ||
'space-before-function-paren': [ | ||
ERROR, | ||
{anonymous: 'never', named: 'never'}, | ||
], | ||
}, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
dist | ||
|
||
# Logs | ||
logs | ||
*.log | ||
npm-debug.log* | ||
|
||
# Runtime data | ||
pids | ||
*.pid | ||
*.seed | ||
|
||
# Directory for instrumented libs generated by jscoverage/JSCover | ||
lib-cov | ||
|
||
# Coverage directory used by tools like istanbul | ||
coverage | ||
|
||
# nyc test coverage | ||
.nyc_output | ||
|
||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) | ||
.grunt | ||
|
||
# node-waf configuration | ||
.lock-wscript | ||
|
||
# Compiled binary addons (http://nodejs.org/api/addons.html) | ||
build/Release | ||
|
||
# Dependency directories | ||
node_modules | ||
jspm_packages | ||
|
||
# Optional npm cache directory | ||
.npm | ||
|
||
# Optional REPL history | ||
.node_repl_history |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
sudo: false | ||
language: node_js | ||
cache: | ||
directories: | ||
- node_modules | ||
notifications: | ||
email: false | ||
node_js: | ||
- '6' | ||
before_install: | ||
- npm i -g npm@^3.0.0 | ||
before_script: | ||
- npm prune | ||
script: | ||
- npm run check | ||
- npm run coverage | ||
- npm run build | ||
after_success: | ||
- npm run semantic-release | ||
branches: | ||
except: | ||
- /^v\d+\.\d+\.\d+$/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
{ | ||
"name": "@safareli/quasi", | ||
"version": "0.0.0-placeholder", | ||
"description": "Combination of a quasi applicative functor and quasi monad", | ||
"main": "dist/quasi.js", | ||
"scripts": { | ||
"lint": "eslint --no-ignore .eslintrc.js --ext js src test tools *.js", | ||
"watch": "nodemon -q -x 'tap test/*.js'", | ||
"test": "tap test/*.js --coverage", | ||
"coverage": "tap --coverage-report=lcov --no-browser && codecov", | ||
"coverage:open": "tap --coverage-report=lcov", | ||
"coverage:check": "tap --check-coverage --branches 95 --functions 95 --lines 95 --statements 95", | ||
"check": "npm run lint && npm run test -- --no-coverage-report && npm run coverage:check", | ||
"commit": "git-cz", | ||
"prebuild": "rimraf dist", | ||
"build": "run-p build:*", | ||
"build:main": "babel -s --out-dir dist src", | ||
"build:umd": "webpack --output-filename quasi.umd.js", | ||
"build:umd.min": "webpack --output-filename quasi.umd.min.js -p", | ||
"semantic-release": "semantic-release pre && npm publish && semantic-release post" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/safareli/quasi.git" | ||
}, | ||
"keywords": [ | ||
"Functor", | ||
"Apply", | ||
"Applicative", | ||
"Chain", | ||
"ChainRec", | ||
"Monad", | ||
"Semigroup", | ||
"Monoid", | ||
"Setoid", | ||
"fantasy-land" | ||
], | ||
"files": [ | ||
"dist", | ||
"LICENSE", | ||
"README.md" | ||
], | ||
"author": "Irakli Safareli <i.safareli@gmail.com>", | ||
"license": "MIT", | ||
"bugs": { | ||
"url": "https://github.com/safareli/quasi/issues" | ||
}, | ||
"homepage": "https://github.com/safareli/quasi#readme", | ||
"devDependencies": { | ||
"babel-cli": "6.10.1", | ||
"babel-core": "6.10.4", | ||
"babel-eslint": "6.1.0", | ||
"babel-loader": "6.2.4", | ||
"babel-preset-es2015": "6.9.0", | ||
"babel-preset-stage-2": "6.11.0", | ||
"codecov": "1.0.1", | ||
"commitizen": "2.8.2", | ||
"conventional-recommended-bump": "0.2.1", | ||
"cz-conventional-changelog": "1.1.6", | ||
"daggy": "0.0.1", | ||
"eslint": "2.13.1", | ||
"eslint-config-standard": "5.3.1", | ||
"eslint-plugin-promise": "1.3.2", | ||
"eslint-plugin-standard": "1.3.2", | ||
"fantasy-combinators": "0.0.1", | ||
"ghooks": "1.3.0", | ||
"nodemon": "1.9.2", | ||
"npm-run-all": "2.3.0", | ||
"rimraf": "2.5.3", | ||
"semantic-release": "^4.3.5", | ||
"tap": "6.1.1", | ||
"webpack": "1.13.1" | ||
}, | ||
"babel": { | ||
"presets": [ | ||
"es2015", | ||
"stage-2" | ||
] | ||
}, | ||
"release": { | ||
"analyzeCommits": "./tools/releaseAnalyzeCommits" | ||
}, | ||
"config": { | ||
"commitizen": { | ||
"path": "./node_modules/cz-conventional-changelog" | ||
}, | ||
"ghooks": { | ||
"pre-commit": "npm run check" | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
module.exports = { | ||
equals: 'fantasy-land/equals', | ||
concat: 'fantasy-land/concat', | ||
empty: 'fantasy-land/empty', | ||
map: 'fantasy-land/map', | ||
ap: 'fantasy-land/ap', | ||
of: 'fantasy-land/of', | ||
reduce: 'fantasy-land/reduce', | ||
traverse: 'fantasy-land/traverse', | ||
chain: 'fantasy-land/chain', | ||
chainRec: 'fantasy-land/chainRec', | ||
extend: 'fantasy-land/extend', | ||
extract: 'fantasy-land/extract', | ||
bimap: 'fantasy-land/bimap', | ||
promap: 'fantasy-land/promap', | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
const fl = require('./fl.js') | ||
const key$of = '@functional/of' | ||
const key$empty = '@functional/empty' | ||
const isEmpty = m => m[key$empty] === true | ||
const isOf = a => a[key$of] === true | ||
|
||
// `of` createas container for a value which currently has no type. | ||
// result could conforms to specifications: Functor, Apply, | ||
// Applicative, Chain, ChainRec, Monad, Semigroup, Monoid and Setoid | ||
// of :: a => m a | ||
const of = (a) => ({ | ||
[key$of]: true, | ||
value: a, | ||
constructor: of, | ||
toString: () => `<of>(${a})`, | ||
[fl.map]: (f) => of(f(a)), | ||
[fl.ap]: (f) => isOf(f) ? of(f.value(a)) : f.constructor[fl.of](a)[fl.ap](f), | ||
[fl.chain]: (f) => f(a), | ||
[fl.equals]: (b) => { | ||
if (isOf(b)) { | ||
return a === b.value || (typeof a[fl.equals] === 'function' && a[fl.equals](b.value)) | ||
} else if (isEmpty(a)) { | ||
return isEmpty(b) | ||
} else if (typeof b.constructor[fl.of] === 'function' ) { | ||
return b.constructor[fl.of](a)[fl.equals](b) | ||
} else { | ||
return false | ||
} | ||
}, | ||
[fl.concat]: (b) => { | ||
if (isOf(b)) { | ||
return of(a[fl.concat](b.value)) | ||
} else if (isEmpty(b)) { | ||
return of(a) | ||
} else { | ||
return b.constructor[fl.of](a)[fl.concat](b) | ||
} | ||
}, | ||
}) | ||
|
||
const methodNeedsValueErrorTpl = (methodName) => | ||
`can't call '${methodName}' method as current instance does not contain a value` | ||
|
||
// it represents `empty` value of some Monoid type is not know yet like result of `of` | ||
const empty = { | ||
[key$empty]: true, | ||
toString: () => `<empty>`, | ||
constructor: of, | ||
[fl.map]: (_) => { throw new TypeError(methodNeedsValueErrorTpl('map')) }, | ||
[fl.ap]: (_) => { throw new TypeError(methodNeedsValueErrorTpl('ap')) }, | ||
[fl.chain]: (_) => { throw new TypeError(methodNeedsValueErrorTpl('chain')) }, | ||
[fl.concat]: a => a, | ||
[fl.equals]: a => isEmpty(a) || (isOf(a) && isEmpty(a.value)), | ||
} | ||
|
||
of[fl.empty] = empty | ||
of[fl.of] = of | ||
|
||
const chainRecNext = value => ({ isNext: true, value }) | ||
const chainRecDone = value => ({ isNext: false, value }) | ||
of[fl.chainRec] = (f, i) => { | ||
let step = f(chainRecNext, chainRecDone, i) | ||
while (isOf(step) && step.value.isNext) { | ||
step = f(chainRecNext, chainRecDone, step.value.value) | ||
} | ||
if (isOf(step)) { | ||
return of(step.value.value) | ||
} | ||
return step[fl.chain](({ isNext, value }) => | ||
isNext ? step.constructor[fl.chainRec](f, value) : step.constructor[fl.of](value) | ||
) | ||
} | ||
|
||
const foldIfIsOf = (f, a) => isOf(a) ? f(a.value) : a | ||
|
||
module.exports = { | ||
empty, | ||
isEmpty, | ||
of, | ||
isOf, | ||
foldIfIsOf, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
const daggy = require('daggy') | ||
|
||
const Q = require('../../src/quasi.js') | ||
const fl = require('../../src/fl.js') | ||
|
||
const Func = daggy.tagged('run') | ||
|
||
Func[fl.of] = (a) => Func((_) => a) | ||
|
||
Func.prototype[fl.ap] = function(g) { | ||
const f = this | ||
return Func((x) => Q.foldIfIsOf(Func[fl.of], g).run(x)(f.run(x))) | ||
} | ||
|
||
Func[fl.empty] = Func[fl.of](Q.empty) | ||
|
||
Func.prototype[fl.concat] = function(g) { | ||
if (Q.isEmpty(g)) { | ||
return this | ||
} | ||
const f = this | ||
return Func((x) => { | ||
const a = this.run(x) | ||
const b = Q.foldIfIsOf(Func[fl.of], g).run(x) | ||
if (Q.isEmpty(a)) { | ||
return b | ||
} else if (Q.isEmpty(b)) { | ||
return a | ||
} else { | ||
return a[fl.concat](b) | ||
} | ||
}) | ||
} | ||
|
||
module.exports = Func |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
const daggy = require('daggy') | ||
|
||
const Q = require('../../src/quasi.js') | ||
const fl = require('../../src/fl.js') | ||
|
||
const Identity = daggy.tagged('value') | ||
|
||
Identity[fl.of] = (a) => Identity(a) | ||
|
||
Identity[fl.empty] = Identity[fl.of](Q.empty) | ||
|
||
Identity.prototype[fl.equals] = function(b) { | ||
return this.value === b.value || (typeof this.value[fl.equals] == 'function' && this.value[fl.equals](b.value)) | ||
} | ||
|
||
Identity.prototype[fl.chain] = function(f) { | ||
return f(this.value) | ||
} | ||
|
||
|
||
const chainRecNext = value => ({ isNext: true, value }) | ||
const chainRecDone = value => ({ isNext: false, value }) | ||
|
||
Identity[fl.chainRec] = function(f, i) { | ||
var state = chainRecNext(i); | ||
while (state.isNext) { | ||
state = f(chainRecNext, chainRecDone, state.value).value; | ||
} | ||
return Identity(state.value); | ||
|
||
} | ||
|
||
Identity.prototype[fl.concat] = function(b) { | ||
b = Q.foldIfIsOf(Identity[fl.of], b) | ||
if (Q.isEmpty(this.value)) { | ||
return b | ||
} else if (Q.isEmpty(b) || Q.isEmpty(b.value)) { | ||
return this | ||
} else { | ||
return Identity(this.value[fl.concat](b.value)) | ||
} | ||
} | ||
|
||
Identity.prototype[fl.ap] = function(f) { | ||
if (Q.isOf(f)) { | ||
return this.map(f.value) | ||
} else { | ||
return Identity(f.value(this.value)) | ||
} | ||
} | ||
|
||
module.exports = Identity |
Oops, something went wrong.