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 🙏

© 2024 – Pkg Stats / Ryan Hefner

monad-maniac

v0.6.1

Published

monads with right rules

Downloads

153

Readme

Monads

Build status Test coverage NPM version

URLs

You finally made it. You stepped through the looking glass. You learned functional programming. You mastered currying and composition, and followed the path of functional purity. And gradually, you notice a change in the attitude of the other programmers. There’s ever-so-slightly less disdain in their voice when you talk to them. Every so often you’ll get a little nod when you happen to mention immutable data structures. You’ve begun to earn their respect. And yet…

There’s something they won’t talk about. When they think you’re not in earshot, every so often, you’ll overhear the word ‘monad’ discussed in hushed tones. But as soon as they notice you’re there, they change the subject. One day, you pluck up the courage to ask someone. “What’s this monad thing I keep hearing about?” The other programmer just looks at you. After an awkward silence she simply says “I can’t talk about it”. So you ask another programmer and she replies “Maybe when you’ve learned Haskell.” She walks away sadly, shaking her head.

Mystified, you start searching for answers on the Internet. And at first there seems to be plenty of people eager to explain the mysterious monads. But, there’s a problem. It’s as if every single one of them writes in some kind of code. They talk about applicative functors, category theory, algebraic structures and monadic laws. But none of them seem to explain what monads are for. What do they do? Why do they exist? You keep searching and discover article after article trying to come up with some kind of analogy. Monads are like tupperware. Monads are like trees. Monads are like a bucket line. Monads are like hazmat suits. Monads are like burritos. Comparing monads to burritos considered harmful… It starts to drive you mad.

One day, one of the more junior programmers approaches you, a furtive expression on his face. “Look, you’ve got to stop asking questions about monads, OK? It upsets people. Monads are cursed. It’s not that people don’t want to tell you about them. They can’t.” He looks around again and continues in a hushed tone. “Even ol' father Crockford couldn’t break the curse. He tried. In a keynote conference talk and everything. But it got him. He couldn’t do it. Either you figure monads out or you don’t. No one can help you. That’s just how it works.”

© James Sinclair

Maybe

Maybe - this is monad for safe working with data. How ofter do you seen such error?

const foo = {}

foo.bar.baz
...
Uncaught TypeError: Cannot read property 'baz' of undefined
    at <anonymous>:1:9

Maybe can you help you, maybe not... :smirk:

const db = [
  { name: 'foo', id: 1 },
  { name: 'bar', id: 2 },
  { name: 'baz', id: 3 },
]
const user = db.find(({ id }) => id === 2)
// Fine
const greeting = `Hello ${user.name}!`

// ...

const user = db.find(({ id }) => id === 10)
/*
Uncaught TypeError: Cannot read property 'name' of undefined
    at <anonymous>:7:32
*/
const greeting = `Hello ${user.name}!`

// Right way

const user = db.find(({ id }) => id === 10)
// Fine
const greeting = user ? `Hello ${user.name}!` : 'No-one to greet... :('

Typescript can you help, if you forget to add check, you will notify about that. But if your data have a lot of nested optional fields, you will get the hell out of checks on null and undefined, maybe other types.

So, Maybe can you help you! Look at this:

import { Maybe } from 'monad-maniac'

const db = [
  { name: 'foo', id: 1 },
  { name: 'bar', id: 2 },
  { name: 'baz', id: 3 },
]

const user = Maybe.of(db.find({ id }) => id === 2)
// greeting = "Hello, bar!"
const greeting = user
  .map(({ name }) => `Hello, ${name}!`)
  .getOrElse('No-one to greet... :(')

// ...

const user = Maybe.of(db.find({ id }) => id === 10)
// greeting = "No-one to greet... :("
const greeting = user
  .map(({ name }) => `Hello, ${name}!`)
  .getOrElse('No-one to greet... :(')

How to use it?

of

of - factory function for Maybe.

import { Maybe } from 'monad-maniac'

const maybeFoo = Maybe.of('foo') // Just(foo)
const maybeBar = Maybe.of(null) // Nothing()
const maybeBaz = Maybe.of(undefined) // Nothing()

map

map - this is method or pure function Maybe. When data maybe is null or undefined and with the data need to do something, usually used a lot of checks. With Maybe you can forget about it.

import { Maybe } from 'monad-maniac'

type Data = {
  message?: {
    sender?: {
      name?: string
    }
  }
}

const maybeData = Maybe.of<Data>({
  message: {
    sender: {
      name: 'MR. Holmes',
    }
  }
})

const prop = <T, K extends keyof T>(key: K) => (obj: T) => obj[key]

const heyMister: string = maybeData
  .map(prop('message'))
  .map(prop('sender'))
  .map(prop('name'))
  .caseOf({
    Just: (name) => `Hey! ${name}!`,
    Nothing: () => 'Unknown sender'
  })

console.log(heyMister) // Hey! MR. Holmes!
import { Maybe } from 'monad-maniac'

type Data = {
  message?: {
    sender?: {
      name?: string
    }
  }
}

const maybeData = Maybe.of<Data>({})

const prop = <T, K extends keyof T>(key: K) => (obj: T) => obj[key]

const heyMister: string = maybeData
  .map(prop('message'))
  .map(prop('sender'))
  .map(prop('name'))
  .caseOf({
    Just: (name) => `Hey! ${name}!`,
    Nothing: () => 'Unknown sender'
  })

console.log(heyMister) // Unknown sender

caseOf && getOrElse

This functions serve one purpose - unwrapping Maybe.

import { Maybe } from 'monad-maniac'

const just = Maybe.of(10)
const nothing = Maybe.of<number>(null)

const square = (x: number): number => x * x

// getOrElse
const justResult: ?number = just.map(square).getOrElse(undefined) // 100
const justMoreResult: number = just.map(square).getOrElse(0) // 100
const nothingResult: number = nothing.map(square).getOrElse(0) // 0
const nothingMoreResult: ?number = nothing
  .map(square)
  .getOrElse(undefined) // undefined

// caseOf
const justUnwrapped: number = just.caseOf({
  Just: square,
  Nothing: Infinity,
}) // 100
const nothingUnwrapped: number = nothing.caseOf({
  Just: square,
  Nothing: Infinity,
}) // Infinity

join

If need to get Maybe from Maybe the function is irreplaceable.

import { Maybe } from 'monad-maniac'

const just = Maybe.of(10)
const maybeJust = just.map((x) => Maybe.of(x + 5)) // Just(Just(15))
const justFifteen = maybeJust.join() // Just(15)

// ...
maybeJust
  .join() // Just(15)
  .join() // Nothing()
  .join() // Nothing()
  .join() // Nothing()
  .join() // Nothing()
  .join() // Nothing()

chain

This function like Maybe.map but returns not Maybe but what will be result of callback function.

import { Maybe } from 'monad-maniac'

const just = Maybe.of(10)
const divided = just.chain((x) => Maybe.of(x / 2)) // 5
const none = just.chain((x) => Maybe.of(x > 10000 ? x / 2 : undefined)) // Nothing()
const maybeDivided = just.chain((x) => Maybe.of(x > 10000 ? x / 2 : undefined)) // Nothing()

filter

Function filter takes predicate and returns Just if will be returned true and Nothing otherwise.

import { Maybe } from 'monad-maniac'

const just = Maybe.of(10)
const divided = just.map((x) => 20 / x) // Just(2) - ok

const dividedNaN = Maybe.of(0).map((x) => 20 / x) // Just(NaN)... :worried:

// With filter:

const dividedNormally = Maybe
  .of(0)
  .filter((x) => x !== 0)
  .map((x) => 20 / x) // Nothing() - great!
const dividedNormallyJust = Maybe
  .of(2)
  .filter((x) => x !== 0)
  .map((x) => 20 / x) // Just(10) - great!