Giter Site home page Giter Site logo

maybeasy's Introduction

maybeasy

Build Status semantic-release

Whether we like it or not, not every computation in a program is going to return a value. Sometimes there's no value to return. Other times, something goes wrong and we're just not sure what value to return.

In JavaScript we often will return null or undefined to represent the value of Nothing, however we arrive at that value. This can often lead to failures at runtime when we forget (or are unaware) that a value may be nothing. Strict null checking makes this situation tolerable in Typescript, if only by nagging you every place you need to check for Nothing.

Arrays are less prone to these types of failures, because if when there is nothing, we return an empty array. We can safely apply functions to an array without being concerned if there are values present, because an empty array and a populated array have the same interface. Can that same principle be applied to singular values?

Sure it can! The Maybe type offers a way to express that a value may be something, or it may be nothing. Our intuition for mapping over arrays is applicable here.

the functor (this map)

Given a computation that may or may not return a value, we can apply logic to this value by mapping pure functions over the result of the computation. For example:

const fetchSomething = (): Maybe<number> => ...; // <-- may or may not return something

const add2 = (n) => n + 2;

fetchSomething().map(add2); //

In this example, we add2 to the number that we fetched. But if the there is no number -- it's Nothing -- the result of add2 is... Nothing. We won't get a runtime error.

chaining (the flat map)

Let's say that we have two computations. Both may return nothing, but one of the computations depends on the other.

const fetchSomething = (): Maybe<number> => ...;

const fetchSomethingElse = (n: number): Maybe<string> => ...; // <-- also may or may not return something

We could use a map here, as in this examples:

fetchSomething().map(fetchSomethingElse);

The problem with this is that we will end up a maybe nested inside another maybe. You intuition for Arrays applies here, too; if we map over an Array with a function that returns an Array, we end up with an Array of Arrays. That same thinking applies here; we'll end up with Maybe<Maybe<string>>.

To chain computations that both may return nothing, we need a different tool: andThen. We can rewrite our previous example, but just replace map with andThen:

fetchSomething().andThen(fetchSomethingElse);

If either computation is Nothing, the result is nothing. If both computations succeed, then we have Maybe<string>.

building an object

A common pattern in javascript is build an object from a set of computations. When those computations may or may not return a value, it can be useful to chain them together using Maybe.

Given our functions, you can chain them together using andThen. It looks like this:

fetchSomething().andThen(a => fetchSomethingElse.andThen(b => just({ a, b })));

If the object is fairly complex, this nesting can be quite deep.

fetchSomething()
.andThen(a =>
  fetchSomethingElse().andThen(b =>
    fetchC().andThen(c =>
      fetchD().andThen(d =>
        fetchE().andThen(e =>
          ({ a, b, c, d, e })
        )
       )
      )
    );

This is barely distinguishable from callback hell. The assign method helps flatten this out by allowing us to build an object incrementally. Here's the last code example using assign:

just({})
  .assign('a', fetchSomething())
  .assign('b', fetchSomethingElse())
  .assign('c', fetchC())
  .assign('d', fetchD())
  .assign('e', fetchE());

assign also accepts a function that returns a Maybe value as the second argument. Use this when you need to calculate one value of the object, based on a previously calculated value. For example:

just({})
  .assign('a', just(8))
  .assign('b', scope => just(scope.a + 42)); // --> Just { a: 8, b: 50 }

unwrapping the value

At some point, we may need to send our result to another part of the system. The other part of the system may not understand Maybe values. Or possibly this value needs to be serialized as a string for sending to a third party. We need a safe way to unwrap this value. For this purpose we have getOrElse and getOrElseValue.

getOrElse and getOrElseValue will return the value if it is present (a Just), but also requires us to provide a default value, in the case that we have Nothing. getOrElseValue is strict and takes a value of the generic type of the Maybe. getOrElse is lazy. It takes a function that returns a type of the generic type of the Maybe. The function will only be evaluated if the Maybe is Nothing. Prefer usinf getOrElse if the default value is expensive to calculate.

This makes unwrapping the value safe.

putting it all together

We can, of course, chain and map all we want to create a pipeline of data processors. At the end we can unwrap our value for consumption by humans or other systems. For example:

fetchSomething()
  .map(add2)
  .andThen(fetchSomethingElse)
  .getOrElse('No data');

install

npm install --save maybeasy

yarn add maybeasy

usage

import { just, nothing } from 'maybeasy';

function parse(s) {
  try {
    return just(JSON.parse(s));
  } catch (e) {
    return nothing();
  }
}

docs

API

maybeasy's People

Contributors

kofno avatar davidray avatar joegesualdo avatar pjrebsch avatar dependabot[bot] avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.