Security News
GitHub Removes Malicious Pull Requests Targeting Open Source Repositories
GitHub removed 27 malicious pull requests attempting to inject harmful code across multiple open source repositories, in another round of low-effort attacks.
npm install --save monadsjs
Don't forget to check tests.
It's the most basic monad implementation which only wraps a value. It doesn't make much sense to use this monad as is. Understanding Identity monad is quite crucial to move forward. It can be a starting point for any new monad.
// Identity.unit :: a -> M a
// Identity.bind :: (a -> M b) -> M b
// Identity.map :: (a -> b) -> M b
Identity.unit("Monads are awesome!")
.bind(str => Identity.unit(str.split(" ")))
.map(words => words.length);
// Identity(3)
Maybe monad represents a value (Just
) or monadic zero (Nothing
). It's very convinient way to
literally, let your code fail. Instead of writing multiple checks and try-catches just check type of
the value at the end of transformations chain. In this particular implementation Maybe is just a
union type which exists only if you are using TypeScript.
Just wraps actual value.
// Just.unit :: a -> Just a
// Just.bind :: (a -> Just b | Nothing) -> Just b | Nothing
// Just.map :: (a -> b) -> Just b | Nothing
Just.unit("Monads are awesome!")
.bind(str => Just.unit(str.split(" ")))
.map((words: string[]) => words.length);
// Just(3)
At that point it's really similar to Identity monad. Things looks different when Nothing comes in.
Nothing can be explicity returned from function passed to bind or when error occures. Further
execution is stopped. In the following example double
is not going to be called due to TypeError
throwed in firstWordLength
when empty array is passed.
// Nothing.unit :: () -> Nothing
// Nothing.bind :: (a -> Just b | Nothing) -> Nothing
// Nothing.map :: (a -> b) -> Nothing
const firstWordLength = words => words[0].length;
const double = n => n * 2;
Just.unit([])
.bind(strs => Just.unit(firstWordLength(strs)));
.map(double);
// Nothing()
Either monad is almost like a Maybe monad. Right
and Just
are basically the same. Either unlike
Maybe doesn't have monadic zero. Left
is supposed to wrap Error
. Left
can be explicity
returned from function passed to bind or when error occures. In this particular implementation
Either is just a union type which exists only if you are using TypeScript. In the following
example double
is not going to be called due to TypeError
throwed in firstWordLength
when empty array is passed.
// Right.unit :: a -> Right a
// Right.bind :: (a -> Right b | Left b) -> Right b | Left b
// Right.map :: (a -> b) -> Right b | Left b
Right.unit("Monads are awesome!")
.bind(str => Right.unit(str.split(" ")))
.map((words: string[]) => words.length);
// Right(3)
// Left.unit :: a -> Left a
// Left.bind :: (a -> Right b | Left b) -> Left a
// Left.map :: (a -> b) -> Left a
const firstWordLength = words => words[0].length;
const double = n => n * 2;
Right.unit([])
.bind(strs => Right.unit(firstWordLength(strs)))
.map(double);
// Left(TypeError: Cannot read property 'length' of undefined)
IO monad was invented to make it possible to perform side effects in pure functional languages
(here I have Haskell in mind). In JavaScript we can take an advantage of IO monads to change unpure
functions into pure which makes them easy to test. This implementation is also
a Setoid. IO.equals
makes it
easy to deeply compare two IO monads.
// IO.unit :: (a, ...) -> IO a, [...]
// IO.bind :: ((a, ...) -> IO) -> IO a, [...]
// IO.run :: () -> void
function sayHello(name) {
return IO.unit(alert, `Hello ${name}!`);
}
const m = sayHello("World"); // IO(sayHello, ["World"])
assert(m.equals(IO.unit(alert, "Hello World!"))); // passes
m.run(); // alerts: Hello World!
Promise out of the box is a great Continuation monad implementation! Promise.resolve
corresponds
to unit
and Promise.then
corresponds to bind
. Provided Continuation implementation is a minimal
wrapper for Promise with methods you know from other monads (bind
and unit
). Don't use it, use
Promise.
// Continuation.unit :: a -> Continuation a
// Continuation.bind :: (a -> b) -> Continuation b
Continuation.unit(fetch("https://api.github.com/users/octocat"))
.bind(response => response.json());
// Continuation(<Promise>{ "login": "octocat", "id": ... })
List monad is a clever one. List constructor accepts Iterable
and allows for lazy transformations.
It is achieved using generators. What is more, List implements Symbol.iterator
so you can iterate
through it like any regular iterator.
// List.unit :: a -> List a
// List.bind :: (a -> List b) -> List b
// List.map :: (a -> b) -> List b
// List.forEach :: (a -> void) -> void
const lazySpy = sinon.spy();
const nextLazySpy = sinon.spy();
const m = List.of([1, 2, 3])
.map(x => {
lazySpy();
return x + 1;
}).map(x => {
nextLazySpy();
return x + 1;
});
// List([object Generator])
const asIterable = m[Symbol.iterator]();
// no computation was done so far
assert(lazySpy.notCalled);
assert(nextLazySpy.notCalled);
assert(asIterable.next().value === 3);
// only first value was computed
assert(lazySpy.calledOnce);
assert(nextLazySpy.calledOnce);
assert(asIterable.next().value === 4);
assert(lazySpy.calledTwice);
assert(nextLazySpy.calledTwice);
assert(asIterable.next().value === 5);
assert(lazySpy.calledThrice);
assert(nextLazySpy.calledThrice);
Monad next is a bit different approach to implementing monads in JavaScript. It requires ::
bind
operator wich is not yet supported in TypeScript (shame on you TypeScript, ave Babel!) and having
types when implemening monads is more important for me at this very moment.
const List = {
*unit(iterable) {
yield* iterable;
},
*bind(fn) {
for (let x of this) {
yield fn(x);
}
}
};
const m = List.unit([1, 2, 3])::List.bind(x => x + 1)::List.bind(x => x + 1);
0.0.3
FAQs
Ready to use monads in examples
The npm package monadsjs receives a total of 1 weekly downloads. As such, monadsjs popularity was classified as not popular.
We found that monadsjs demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
GitHub removed 27 malicious pull requests attempting to inject harmful code across multiple open source repositories, in another round of low-effort attacks.
Security News
RubyGems.org has added a new "maintainer" role that allows for publishing new versions of gems. This new permission type is aimed at improving security for gem owners and the service overall.
Security News
Node.js will be enforcing stricter semver-major PR policies a month before major releases to enhance stability and ensure reliable release candidates.