All Projects → cbowdon → Tsmonad

cbowdon / Tsmonad

Licence: mit
Little monad library designed for TypeScript

Programming Languages

javascript
184084 projects - #8 most used programming language
typescript
32286 projects

Labels

Projects that are alternatives of or similar to Tsmonad

tagless-final-example
An example of how to create services using tagless final
Stars: ✭ 25 (-93.4%)
Mutual labels:  monad
clarity
Functional programming library for OCaml
Stars: ✭ 59 (-84.43%)
Mutual labels:  monad
Scriptum
A fool's scriptum on functional programming
Stars: ✭ 346 (-8.71%)
Mutual labels:  monad
hkts
Functional programming tools: option, either, task, state, optics, etc.
Stars: ✭ 20 (-94.72%)
Mutual labels:  monad
free-arrow
Implementation of the Free Arrow in Scala and other helpful tools for working with Arrows
Stars: ✭ 14 (-96.31%)
Mutual labels:  monad
Rationale
Ramda inspired library of helper functions for ReasonML
Stars: ✭ 275 (-27.44%)
Mutual labels:  monad
harmony
C++ Monadologie
Stars: ✭ 26 (-93.14%)
Mutual labels:  monad
Fp Resources
Functional programming great resources
Stars: ✭ 369 (-2.64%)
Mutual labels:  monad
reflow
A light-weight lock-free series/parallel combined scheduling framework for tasks. The goal is to maximize parallelism in order to minimize the execution time overall.
Stars: ✭ 23 (-93.93%)
Mutual labels:  monad
Magic In Ten Mins
十分钟魔法练习
Stars: ✭ 327 (-13.72%)
Mutual labels:  monad
cefal
(Concepts-enabled) Functional Abstraction Layer for C++
Stars: ✭ 52 (-86.28%)
Mutual labels:  monad
Narvalo.NET
Applied functional patterns for C#. Money and Currency types. MVP framework. (Obsolete)
Stars: ✭ 16 (-95.78%)
Mutual labels:  monad
Effectfuljs
JavaScript embedded effects compiler
Stars: ✭ 287 (-24.27%)
Mutual labels:  monad
MtacAR
Mtac in Agda
Stars: ✭ 29 (-92.35%)
Mutual labels:  monad
Language Ext
C# functional language extensions - a base class library for functional programming
Stars: ✭ 3,964 (+945.91%)
Mutual labels:  monad
cpsfy
🚀 Tiny goodies for Continuation-Passing-Style functions, fully tested
Stars: ✭ 58 (-84.7%)
Mutual labels:  monad
asynqro
Futures and thread pool for C++ (with optional Qt support)
Stars: ✭ 103 (-72.82%)
Mutual labels:  monad
Kotlin Result
A multiplatform Result monad for modelling success or failure operations.
Stars: ✭ 369 (-2.64%)
Mutual labels:  monad
Fun Task
Abstraction for managing asynchronous code in JS
Stars: ✭ 363 (-4.22%)
Mutual labels:  monad
Monio
Async-capable IO monad for JS
Stars: ✭ 311 (-17.94%)
Mutual labels:  monad

TsMonad

  • a simple and pragmatic monad library
  • designed for TypeScript
  • with the aim of limiting errors due to unhandled nulls

Status

Sorry folks, I don't have time to actively maintain this project. Glad it has been of help to some people and thanks everyone for your contributions!

I'm not seeking maintainer to take over - of course feel free to fork if you'd like to continue developing TsMonad.

Description

This library provides implementations of the most useful monads outside of Haskell (subjectively, this is Maybe and Either). It also provides a strongly-typed emulation of pattern matching to help enforce program correctness.

I won't presume to attempt a monad tutorial here. There are several online - I recommend Douglas Crockford's Monads & Gonads talk.

License

MIT

Usage

This library will work with vanilla ES3 JavaScript with node or in the browser. However, it is far better with TypeScript.

Node:

var TsMonad = require('tsmonad');

Browser:

<script src="node_modules/tsmonad/dist/tsmonad.js"></script>

TypeScript definitions:

/// <reference path="node_modules/tsmonad/dist/tsmonad.d.ts" />

Examples (in TypeScript)

You can see the unit tests for the examples below online here and view the source in test/examples.ts.

Pattern matching emulation

var turns_out_to_be_100 = Maybe.just(10)
    .caseOf({
        just: n => n * n,
        nothing: () => -1
    });

var turns_out_to_be_a_piano = Maybe.nothing<number>()
    .caseOf({
        just: n => n * n,
        nothing: () => -1 // joke, it's negative one not a piano
    });

var turns_out_to_throw_a_compiler_error = Maybe.just(321)
    .caseOf({
        just: n => 999,
        // tsc will tell you that this "does not implement 'nothing'"
        // helping to enforce correct handling of all possible paths
    });

General Maybe usage

The Maybe monad can simplify processing of values that may not exist:

var canRideForFree = user.getAge()  // user might not have provided age, this is a Maybe<number>
    .bind(age => getBusPass(age))   // not all ages have a bus pass, this is a Maybe<BusPass>
    .caseOf({
        just: busPass => busPass.isValidForRoute('Weston'),
        nothing: () => false
    });

Without Maybe, this would be something like:

var canRideForFree,
    age = user.getAge(); // might be null or undefined

if (age) {
    var busPass = getBusPass(age); // might be null or undefined
    if (busPass) {
        canRideForFree = busPass.isValidForRoute('Weston');
    }
}
canRideForFree = false;

Please excuse the messy var scoping and implicit any types in the above. Again, the neat thing about the caseOf method is that it forces you to consider the failure case - it's not always obvious if you're missing a branch of your if-else statement, until it blows up at runtime.

There are some convenience methods in Maybe:

user.getLikesCookies().defaulting(false); // Maybe<false>
user.getLikesCookies().valueOr(false); // false
user.getLikesCookies().valueOrCompute(() => expensiveCalculation());
user.getLikesCookies().valueOrThrow(new Error());

// Maybe.just({ three: 3, hi: 'hi'})
Maybe.sequence<number|string>({ three: Maybe.just(3), hi: Maybe.just('hi') });

// Maybe.nothing
Maybe.sequence<number>({ three: Maybe.just(3), hi: Maybe.nothing() });

General Either usage

var canRideForFree = user.getAge()  // either 42 or 'Information withheld' - type of Either<string,number>
    .bind(age => getBusPass(age))   // either busPass or 'Too young for a bus pass' - type of Either<string,BusPass>
    .caseOf({
        right: busPass => busPass.isValidForRoute('Weston'),
        left: errorMessage => { console.log(errorMessage); return false; }
    });

General Writer usage

Somewhat contrived example of recording arithmetic operations:

var is_true = Writer.writer(['Started with 0'], 0)
    .bind(x => Writer.writer(['+ 8'], x + 8))
    .bind(x => Writer.writer(['- 6', '* 8'], 8 * (x - 6)))
    .caseOf({
        writer: (s, v) => v === 16 && s.join(', ') === 'Started with 0, + 8, - 6, * 8'
    }));

The lift method (fmap)

The lift method takes a lambda, applies it to the wrapped value and calls the unit function of the monad on the result (e.g. for Maybe it calls just). Useful when you want to bind to a function that doesn't return a monad.

var turns_out_to_be_true = Maybe.just(123)
    .lift(n => n * 2)
    .caseOf({
        just: n => n === 246,
        nothing: () => false
    });

Note that for Maybe, if the lifted function returns null or undefined then it returns Nothing rather than wrapping a null in a Just, which is perverse.

FAQ and apologies

Why only Maybe, Either and Writer (so far)?

These monads are the most obviously useful in JavaScript's world of unrestricted mutable state and side effects. I'm currently evaluating which other common monads offer enough benefit to be worth implementing in TypeScript.

Where's monad transformers?

Sorry. One day. But for the moment it's not practicable to do this without support for higher-kinded types.

Is it Fantasy Land conformant?

Yes - there are aliases for Fantasy Land interfaces of Functor and Monad.

"Fantasy land logo"

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].