npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

m.m

v1.0.3

Published

A few missing monads for javascript and typescript

Downloads

11

Readme

MM

A few Missing Monads for Javascript and Typescript.

  • Option (aka Maybe): represents optional values and avoids ugly tests for null, undefined or NaN
  • Seq: an ordered sequence of values with numerous methods to manipulate it
  • Range: numeric values in range [start;end) with non-zero step value step
  • Try: a computation that may either result in an error, or return a successfully computed value and that may be easily chained with other computations

A small library with no external dependencies that implements a few useful Monads for functional programming.

  • no external dependencies
  • works with ES5
  • based on iterators with lazy evaluation
  • largely inspired from Scala
  • typings automatically loaded when programming in Typescript
  • excellent tests coverage

Write shorter immutable code

Instead of

let value;
if (typeof input === 'undefined' || input === null) {
    value = getDefaultValue()
}
else {
   value = calculateFromInput(input)
}

write

const value = option(input).map(calculateFromInput).getOrElse(getDefaultValue) 

Write lazy evaluated code

const mySeq = seq(hugeArray).drop(2).map(expensiveOp).takeFirst(3)
mySeq.toArray
  

mySeq is not evaluated (iterated) until toArray is called on it, and when it is, only five iterations on the Seq and 3 calls to map are performed

Usage

Typescript / ES6: import { some, seq, .. } from 'm.m'

ES5 var MM = require('m.m')

License

MIT

TODO, Contributing, etc..

Most Wanted: Either,...

You are most welcome to contribute by opening new Pull Requests. For new Monads, please get inspiration from the Scala definitions and extend Collection for the implementation

API

Option

Represents optional values.


/**
 * Creates a None, i.e. an empty Option
 */
function none(): Option<A>

/**
 * Create a Some i.e. an Option holding a value
 */
function some<A>( value?: A ): Option<A>

/**
 * Create a None if value is undefined or null or NaN
 * otherwise create a Some holding that value
 */
function option<A>(value?: A): Option<A>

The most idiomatic way to use an Option is to treat it as a collection or monad and use map, flatMap, filter, or foreach:

const name = option( request.getParameter('name') )
const upper = name.map( n => n.trim() ).filter( n => n.length !== 0 ).map( n => n.toUpperCase() )
console.log(upper.getOrElse( () =>  "" ) )

Seq

A Seq is an ordered sequence of values

/**
 * Create a Seq
 */
function seq<A>( ...values: any[]  ): Seq<A>

A Seq can be created from

  • a list of disctrete values e.g. seq( 1, 2, 3 )
  • any Iterable including an Array, a String, another Seq, an ES6 Map, etc... e.g. seq( [1 ,2, 3] ), seq('abcd')

Examples:

seq('dlroW olleH').reverse.mkString(' ')    // 'H e l l o   W o r l d'

seq(1, 2, 'a', 3, 'b', 4).collect( n => !isNaN(n) )( n => n*2 ).mkString('[', ',', ']')    // '[2,4,6,8]'

seq( seq( [1, 2] ), 3, seq( 4, 5 ) ).flatten().toArray // [ 1, 2, 3, 4, 5 ]

Range

The Range class represents numeric values in range with non-zero step value step. A Range is a special case of Seq.

/**
 * Create a range of integers of the specified length starting at 0
 */
function range( length: number ): Range;

/**
 * Create a range from the specified start to the element (end - 1) included in steps of 1
 */
function range( start: number, end: number ): Range

/**
 * Create a range from start to (end - step) included
 */
function range( start: number, end: number, step: number ): Range

Ranges are not indexed but based on (lazy) iterators; it is therefore possible to manipulate Infinity in Ranges:

range(0, Infinity).take(10).toArray   //[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]

Try

A Try represents a computation that may either result in an error, or return a successfully computed value.

A computation can be created by passing function without arguments to tri().

/**
 * Wraps this computation in a Try
 */
function tri<A>( computation: ( ) => A ): Try<A>

Please note that the function is spelled with an 'i' to avoid a conflict with the reserved keyword try

As with other monads of this library, Try is lazy and the computation will only be performed when attempting to "extract" a result.

What is interesting with Try is the ability to chain error throwing functions with a fail fast behavior, and potentially recover from these error(s)

function divide( numerator: any, denominator: any ): Try<number> {

    const parseNumerator = () => option( parseFloat( numerator ) ).orThrow( () => "Invalid numerator" );
    const parseDenominator = () => option( parseFloat( denominator ) ).orThrow( () => "Invalid denominator" );

    //chain error throwing functions
    return tri( parseNumerator ).flatMap( num => tri( parseDenominator ).map( den => num / den ) )
}

//now, divide(), can itself be chained
divide(num, den).map(x => x*2)

//or can be "recovered" from

divide( num, den )
    .recover( ( e: Error ) => {
                console.log('Divide failed. '+e.message+'. Returning Infinity')
                return Infinity
            } )
   .get

//divide('blah',3) -> Infinity