All Projects β†’ getify β†’ Monio

getify / Monio

Licence: mit
Async-capable IO monad for JS

Programming Languages

javascript
184084 projects - #8 most used programming language
js
455 projects

Projects that are alternatives of or similar to Monio

Purefun
Functional Programming library for Java
Stars: ✭ 37 (-88.1%)
Mutual labels:  monad, monads, functional-programming
Pratica
πŸ₯ƒ Functional Algebraic Data Types
Stars: ✭ 246 (-20.9%)
Mutual labels:  monads, functional-programming, fp
fpEs
Functional Programming for EcmaScript(Javascript)
Stars: ✭ 40 (-87.14%)
Mutual labels:  monads, fp, monad
Fun Task
Abstraction for managing asynchronous code in JS
Stars: ✭ 363 (+16.72%)
Mutual labels:  monad, functional-programming, fp
Bow
🏹 Bow is a cross-platform library for Typed Functional Programming in Swift
Stars: ✭ 538 (+72.99%)
Mutual labels:  monad, functional-programming, fp
Kotlin Result
A multiplatform Result monad for modelling success or failure operations.
Stars: ✭ 369 (+18.65%)
Mutual labels:  monad, functional-programming, fp
Language Ext
C# functional language extensions - a base class library for functional programming
Stars: ✭ 3,964 (+1174.6%)
Mutual labels:  monad, monads, functional-programming
Learn Fp
learn-by-doing course/tutorial for functional programming on scala
Stars: ✭ 548 (+76.21%)
Mutual labels:  monad, monads, functional-programming
Fpgo
Monad, Functional Programming features for Golang
Stars: ✭ 165 (-46.95%)
Mutual labels:  monad, monads, functional-programming
Cats Mtl
cats transformer type classes.
Stars: ✭ 238 (-23.47%)
Mutual labels:  monad, functional-programming
Design-Patterns
Project for learning and discuss about design patterns
Stars: ✭ 16 (-94.86%)
Mutual labels:  fp, monad
function-composition-cheatsheet
Composition of Functions
Stars: ✭ 24 (-92.28%)
Mutual labels:  fp, monad
Funcadelic.js
Functional programming and category theory for everyday JavaScript development
Stars: ✭ 183 (-41.16%)
Mutual labels:  monad, functional-programming
Fluture
πŸ¦‹ Fantasy Land compliant (monadic) alternative to Promises
Stars: ✭ 2,249 (+623.15%)
Mutual labels:  monad, functional-programming
fnts
Ξ» Minimal Functional Programming Utilities for TypeScript & JavaScript
Stars: ✭ 75 (-75.88%)
Mutual labels:  fp, monad
Functional Examples
Examples with Functional JavaScript, following Professor Frisby's course
Stars: ✭ 179 (-42.44%)
Mutual labels:  monad, functional-programming
Prelude Ts
Functional programming, immutable collections and FP constructs for typescript and javascript
Stars: ✭ 315 (+1.29%)
Mutual labels:  functional-programming, fp
Mostly Adequate Guide Chinese
ε‡½ζ•°εΌηΌ–η¨‹ζŒ‡εŒ—δΈ­ζ–‡η‰ˆ
Stars: ✭ 2,093 (+572.99%)
Mutual labels:  monad, functional-programming
apropos
Fast strong typed 'Either' data structure for typescript and flow
Stars: ✭ 20 (-93.57%)
Mutual labels:  fp, monad
Shapeless
Generic programming for Scala
Stars: ✭ 3,207 (+931.19%)
Mutual labels:  functional-programming, fp

Monio

Build Status npm Module Coverage Status

Monio (mō'ne-yo) is an async-capable IO Monad (including "do" style) for JS, with several companion monads thrown in.

See It In Action

Overview

Monio balances the power of monads -- often dismissed by the non-FP programmer as academic and convoluted -- while pragmatically embracing the reality of the vast majority of JS programs: paradigm mixture (some OO, some FP, and probably a lot of imperative procedural code).

The driving inspiration behind Monio is the IO monad -- useful for managing side-effects -- that additionally supports "do-style" syntax with JS-ergonomic asynchrony (based on promises) in the style of familiar async..await code. IOs are lazy, so their operations are not triggered until the run(..) method is called.

Monio's IO is a transformer over promises, which means that when promises are produced in an IO, they are automatically unwrapped; of course, that means subsequent IO operations are deferred. If any IO in a chain produces a promise, run(..)'s result will be "lifted" to a promise that resolves when the entire IO chain is complete. Otherwise, the IO instance and its run(..) call will operate synchronously and immediately produce the result.

Monio intentionally chooses to model asynchrony over promises instead of Task monads, because of its goal of balancing FP with pragmatic and idomatic non-FP JS. However, there's nothing that should prevent you from using a Task monad with Monio if you prefer.

IO's "do-style" syntax is specified with the do(..) method (automatically lifts the IO to promise-producing asynchrony), which accepts JS generators (including "async generators": async function *whatever(){ .. }). yield is used for chaining IOs (which can produce promises to defer), whereas await is for explicitly deferring on a promise that's not already wrapped in an IO. The resulting style of code should be more broadly approachable for JS developers, while still benefitting from monads.

IO's do(..) is JS-ergonomic for exception handling. Uncaught JS exceptions become promise rejections, and IO-produced promise rejections are try..catch'able. IO also supports modeling exception handling through Either monads: doEither(..) transforms uncaught exceptions into Either:Left values, and recognizes IO-produced Either:Left values as try..catch'able exceptions.

Monio's IO is also a Reader monad, which carries side-effect read environments alongside IO operations.

Monio includes several supporting monads/helpers in addition to IO:

  • Maybe (including Just and Nothing)

  • Either

  • Monio-specific AsyncEither (same promise-transforming behavior as IO)

  • IOEventStream(..): creates an IO instance that produces an "event stream" -- an async-iterable consumable with a for await..of loop -- from an event emitter (ie, a DOM element, or a Node EventEmitter instance)

For the FP savvy

Monio's IO models a function e => IO a (Promise b c), which is strong enough to capture (optional) environment passing, side effects, async, and error handling without the pain of composing each type separately.

Typically IO does not take an argument, but given one, it acts like an effectful Reader. In addition, it can model sync or async functions so the inner Promise becomes optional.

In that way, you can think of it as ReaderT (IOT (Promise|Identity a b)) where Promise gets swapped for Identity if you're not doing async.

Monio's IO is like a JS-style ZIO/RIO where we have all the functionality we need wrapped up in 1 monad.

Using Monio

To use monads/helpers from Monio, first import them:

  • CJS programs/modules in Node:

    var { Maybe, IO } = require("monio");
    
    // or:
    var Just = require("monio/just");
    
  • ESM in Node:

    import { Maybe, IO } from "monio";
    
    // or:
    import Just from "monio/just";
    

    Note: As of v0.20.0, the previously required ESM import specifier segment /esm in Monio import paths has been deprecated (and will eventually be removed), in favor of unified import specifier paths via Node Conditional Exports. For ESM import statements, always use the specifier style "monio" or "monio/just", instead of "monio/esm" and "monio/esm/just", respectively.

  • ESM in browser:

    import { Maybe, IO } from "/path/to/monio/dist/esm/index.mjs";
    
    // or:
    import Just from "/path/to/monio/dist/esm/just.mjs";
    
  • UMD in browser:

    <script src="/path/to/monio/dist/umd/bundle.js"></script>
    
    <!-- or -->
    <script src="/path/to/monio/dist/umd/just.js"></script>
    

Once the monads are imported into your module/program, instances are created from functions (no new constructors necessary):

var helloWorld = Just("Hello World");

helloWorld._inspect();
// Just("Hello World")

Just.is(helloWorld);
// true

Monio's monads can of course be used together in various expected ways:

var helloWorld = Just("Hello World");
var greeting = Maybe(helloWorld);
var log = str => IO(() => console.log(str));

var main = IO.do(function *main(){
    var msg = greeting.map(m => `${ m }!!`);

    // Uncomment this line to swap in an empty maybe
    // msg = Maybe.from(null);

    yield msg.fold(IO.of,log);
});

main.run();
// Hello World!!

Tests

A test suite is included in this repository, as well as the npm package distribution. The default test behavior runs the test suite using the files in src/.

  1. The tests are run with QUnit.

  2. To run the test utility with npm:

    npm test
    
  3. To run the test utility directly without npm:

    qunit
    

Test Coverage

Coverage Status

If you have NYC (Istanbul) already installed on your system (requires v14.1+), you can use it to check the test coverage:

npm run coverage

Then open up coverage/lcov-report/index.html in a browser to view the report.

Note: The npm script coverage:report is only intended for use by project maintainers. It sends coverage reports to Coveralls.

License

All code and documentation are (c) 2021 Kyle Simpson and released under the MIT License. A copy of the MIT License is also included.

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].