Skip to content

Commit

Permalink
fixed a few quirks with some helpers (boolean truthiness) and added '…
Browse files Browse the repository at this point in the history
…isMonad(..)' helper
  • Loading branch information
getify committed Jan 19, 2021
1 parent 4b027da commit 9b195a7
Show file tree
Hide file tree
Showing 11 changed files with 56 additions and 33 deletions.
2 changes: 1 addition & 1 deletion README.md
Expand Up @@ -158,4 +158,4 @@ Then open up `coverage/lcov-report/index.html` in a browser to view the report.

## License

All code and documentation are (c) 2020 Kyle Simpson and released under the [MIT License](http://getify.mit-license.org/). A copy of the MIT License [is also included](LICENSE.txt).
All code and documentation are (c) 2021 Kyle Simpson and released under the [MIT License](http://getify.mit-license.org/). A copy of the MIT License [is also included](LICENSE.txt).
2 changes: 1 addition & 1 deletion package.json
@@ -1,7 +1,7 @@
{
"name": "monio",
"description": "Async-capable IO monad for JS",
"version": "0.13.1",
"version": "0.14.0",
"main": "./src/index.js",
"scripts": {
"build": "node scripts/",
Expand Down
4 changes: 2 additions & 2 deletions src/async-either.js
@@ -1,6 +1,6 @@
"use strict";

var { isPromise, } = require("./lib/util.js");
var { isFunction, isPromise, } = require("./lib/util.js");
var Either = require("./either.js");

var brand = {};
Expand Down Expand Up @@ -111,7 +111,7 @@ function fromPromise(pr) {
}

function is(val) {
return val && typeof val._is == "function" && val._is(brand);
return val && isFunction(val._is) && val._is(brand);
}

function fromFoldable(m) {
Expand Down
3 changes: 2 additions & 1 deletion src/either.js
@@ -1,5 +1,6 @@
"use strict";

var { isFunction, } = require("./lib/util.js");
var Just = require("./just.js");

var brand = {};
Expand Down Expand Up @@ -83,7 +84,7 @@ function LeftOrRight(val,isRight = true) {
}

function is(val) {
return val && typeof val._is == "function" && val._is(brand);
return val && isFunction(val._is) && val._is(brand);
}

function fromFoldable(m) {
Expand Down
4 changes: 2 additions & 2 deletions src/io-event-stream.js
Expand Up @@ -244,7 +244,7 @@ function pullFromStreams(streams) {
.map(function callIter(v,idx){
// stream (iterator) waiting for its
// next() call?
if (v && typeof v.next == "function") {
if (v && isFunction(v.next)) {
streams[idx] = (async function getNext(){
var pr = v.next();
try {
Expand Down Expand Up @@ -274,7 +274,7 @@ function pullFromStreams(streams) {
function close(...streams) {
return IO(() => (
Promise.all(streams.map(async function closeStream(stream){
if (stream && typeof stream.return == "function") {
if (stream && isFunction(stream.return)) {
try {
return await stream.return();
}
Expand Down
16 changes: 8 additions & 8 deletions src/io-helpers.js
@@ -1,6 +1,6 @@
"use strict";

var { isPromise, } = require("./lib/util.js");
var { isFunction, isPromise, isMonad, } = require("./lib/util.js");
var IO = require("./io.js");
var Maybe = require("./maybe.js");
var Either = require("./either.js");
Expand Down Expand Up @@ -156,10 +156,10 @@ function els(thens) {
function iReturn(val) {
return IO(env => (
liftIO(env,val)
.chain(v => {
.map(v => {
var ret = { returned: v, };
returnedValues.add(ret);
return IO.of(ret);
return ret;
})
.run(env)
));
Expand All @@ -168,7 +168,7 @@ function iReturn(val) {
function iNot(val) {
return IO(env => (
liftIO(env,val)
.chain(v => IO.of(!v))
.map(not)
.run(env)
));
}
Expand All @@ -179,7 +179,7 @@ function wasReturned(v) {

function liftIO(env,v) {
// monad?
if (v && typeof v == "object" && typeof v.chain == "function") {
if (isMonad(v)) {
// already an IO?
if (IO.is(v)) {
return v;
Expand All @@ -205,12 +205,12 @@ function liftIO(env,v) {
}
}
}
// function?
else if (typeof v == "function") {
// non-monad function?
else if (isFunction(v)) {
return liftIO(env,v(env));
}
// iterator?
else if (v && typeof v == "object" && typeof v.next == "function") {
else if (v && typeof v == "object" && isFunction(v.next)) {
return IO.do(v);
}
// fallback: wrap whatever value this is in an IO
Expand Down
18 changes: 7 additions & 11 deletions src/io.js
@@ -1,6 +1,6 @@
"use strict";

var { isPromise, } = require("./lib/util.js");
var { isFunction, isPromise, } = require("./lib/util.js");
var Either = require("./either.js");

var brand = {};
Expand Down Expand Up @@ -64,8 +64,8 @@ function IO(effect) {

function _inspect() {
return `${publicAPI[Symbol.toStringTag]}(${
typeof effect == "function" ? (effect.name || "anonymous function") :
(effect && typeof effect._inspect == "function") ? effect._inspect() :
isFunction(effect) ? (effect.name || "anonymous function") :
(effect && isFunction(effect._inspect)) ? effect._inspect() :
val
})`;
}
Expand All @@ -81,7 +81,7 @@ function of(v) {
}

function is(v) {
return v && typeof v._is == "function" && v._is(brand);
return v && isFunction(v._is) && v._is(brand);
}

function processNext(next,respVal,outerV,throwEither = false) {
Expand Down Expand Up @@ -171,16 +171,12 @@ function doEither(block) {

function getIterator(block,v) {
return (
typeof block == "function" ? block(v) :
(block && typeof block == "object" && typeof block.next == "function") ? block :
isFunction(block) ? block(v) :
(block && typeof block == "object" && isFunction(block.next)) ? block :
undefined
);
}

function monadFlatMap(m,fn) {
return m[
"flatMap" in m ? "flatMap" :
"chain" in m ? "chain" :
"bind"
](fn);
return getMonadFlatMap(m).call(m,fn);
}
8 changes: 5 additions & 3 deletions src/just.js
@@ -1,5 +1,7 @@
"use strict";

var { isFunction, } = require("./lib/util.js");

var brand = {};

module.exports = Object.assign(Just,{
Expand Down Expand Up @@ -44,8 +46,8 @@ function Just(val) {
return (
typeof val == "string" ? `"${ val }"` :
typeof val == "undefined" ? "" :
typeof val == "function" ? (val.name || "anonymous function") :
val && typeof val._inspect == "function" ? val._inspect() :
isFunction(val) ? (val.name || "anonymous function") :
val && isFunction(val._inspect) ? val._inspect() :
Array.isArray(val) ? `[${ val.map(v => v == null ? String(v) : _serialize(v)) }]` :
String(val)
);
Expand All @@ -58,5 +60,5 @@ function Just(val) {
}

function is(val) {
return val && typeof val._is == "function" && val._is(brand);
return val && isFunction(val._is) && val._is(brand);
}
25 changes: 23 additions & 2 deletions src/lib/util.js
@@ -1,23 +1,44 @@
"use strict";

module.exports = {
getMonadFlatMap,
isFunction,
isPromise,
isMonad,
curry,
};
module.exports.getMonadFlatMap = getMonadFlatMap;
module.exports.isFunction = isFunction;
module.exports.isPromise = isPromise;
module.exports.isMonad = isMonad;
module.exports.curry = curry;


// **************************

function getMonadFlatMap(m) {
return m[
"flatMap" in m ? "flatMap" :
"chain" in m ? "chain" :
"bind"
];
}

function isFunction(v) {
return v && typeof v == "function";
return !!(v && typeof v == "function");
}

function isPromise(v) {
return v && typeof v.then == "function";
return !!(v && isFunction(v.then));
}

// duck-type check for monad'ness
function isMonad(v) {
return !!(
v &&
(typeof v == "object" || isFunction(v)) &&
isFunction(getMonadFlatMap(v))
);
}

function curry(fn,arity = fn.length) {
Expand Down
3 changes: 2 additions & 1 deletion src/maybe.js
@@ -1,5 +1,6 @@
"use strict";

var { isFunction, } = require("./lib/util.js");
var Just = require("./just.js");
var Nothing = require("./nothing.js");

Expand Down Expand Up @@ -86,7 +87,7 @@ function Maybe(val) {
}

function is(val) {
return val && typeof val._is == "function" && val._is(brand);
return val && isFunction(val._is) && val._is(brand);
}

function from(val) {
Expand Down
4 changes: 3 additions & 1 deletion src/nothing.js
@@ -1,5 +1,7 @@
"use strict";

var { isFunction, } = require("./lib/util.js");

var brand = {};

module.exports = Object.assign(Nothing,{
Expand Down Expand Up @@ -35,7 +37,7 @@ function Nothing() {
}

function is(val) {
return val && typeof val._is == "function" && val._is(brand);
return val && isFunction(val._is) && val._is(brand);
}

// default isEmpty(), can be overidden
Expand Down

0 comments on commit 9b195a7

Please sign in to comment.