4.2.0 • Published 9 months ago

jazzi v4.2.0

Weekly downloads
15
License
MIT
Repository
github
Last release
9 months ago

Jazzi: Juan's Algebraic Data Structures

Implementations of common functional structures. Available structures and features:

  • Either
  • Maybe
  • Async
  • All structures have a toPromise and toThenable methods

Installing

From npm registry

npm install jazzi
// or
yarn add jazzi

From denoland

import * as jazzi from 'https://deno.land/x/jazzi/mod.ts'

Usage

This README.md is a summary of all that is available in jazzi. For more details go to API.md

All structures and global functions are exported as named exports from the jazzi module

import { Maybe, Either, Async } from 'jazzi';
// or if you use deno
import { Maybe, Either, Async } from 'https://deno.land/x/jazzi/mod.ts'; 

Constructors and operators are exported as named exports of the structure they are meant to be used on.

import * as M from 'jazzi/Maybe';

M.of(40)['|>'](M.map(x => x + 2)) // Just 42

A wrapper that mimics a fluent interface is also available

import * as M from 'jazzi/Maybe/fluent';

M.of(40).map(x => x + 2)

Conversion between the two styles is possible via the wrap and unwrap operators

import * as M from 'jazzi/Maybe';
import * as F from 'jazzi/Maybe/fluent';

const pipeToFluent = F.wrap(M.of(41));
const fluentToPipe = F.of(41).unwrap();

Summary

From this point onwards, all imports are omitted

All structures have a toThenable function that returns an object complies with the thenable interface. This allows for ease of composition with JS Promises and to be used with async/await syntax. In general, all happy cases return inner value, all adverse cases throw inner value. In versions <=2.2.1, the structure was a thenable with a then function. This caused some implicit behavior and the thenable feature was made opt-in with the toThenable function.

const eitherLeftOrRight = Either.from(/*...*/);
const example = async () => {
    try {
        const x = await eitherLeftOrRight.toThenable()
        console.log(`It was Right ${x}`);
    } catch(e){
        console.log(`It was Left ${e}`)
    }
}

It also comes with a toPromise function that converts any structure to a promise.

Maybe

Maybe represents the possibility of the absensce of value. Just for values, None for no values. The default constructor returns Just of truthy values and None otherwise. Unlike Either where Left and Right both behave like functors, None does not behave like a functor, rather map of a None simply returns the structure unchanged.

Maybe.of(42)    // Just 42
Maybe.of(false) // None

Either

Either represents a value that can be one of two possibilities, either Left or Right (badum tssss). By convention Left is treated as the error case and Right as the happy path but they are just two possibilities. The from constructor receives a left value l and right value r where if r is neither null nor undefined then we get Right r otherwise we get a Left l. There is a curried version of the fromFalsy constructor that was made for convenience. The of constructor is the same as calling the from constructor but passing the same value as both arguments

const default42 = Either.defaultTo(42);
defaultTo42(undefined) // returns Left 42
defaultTo42(6 * 9) // returns Right (6 * 9)

const Right42 = Either.attempt(() => 42) // returns Right 42 
const Left42 = Either.attempt(() => { throw 42 }) // returns Left 42 

Async

The Async structure represents an async computation that may need some input. It can be seen as a mix between IO, Reader and a Promise. Unlike IO, run returns a promise with the result of the computation. Like IO, it is a lazy monad. Like Reader, the run method must receive the environment.

const s42 = Async.Success(42)
const f42 = Async.Fail(42)

await s42.run() // resolves with 42
await f42.run() // rejects with 42

const withEnv = Async.from(async (x) => x + 2)
await withEnv.run(40) // resolves with 42

// Environment can be provided using provide
const withEnvProvided = Async.from(async (x) => x + 2).provide(40)
await withEnvProvided.run() // resolves with 42

// Zip sequences two Asyncs and collects the result in a tuple. Left and Right variants discard one result.
// a.zip(b) is equivalent to a.flatMap(x => b.map(y => [x,y]))
await s42.zip(s42).run() // resolves to [42,42]
await s42.zipRight(Async.Success("right")).run() // resolves to "right"
await Async.Success("left").zipLeft(s42).run() // resolves to "left"

// The only way to recover from a Fail
await f42.recover((e) => Async.Success(e)).run() // resolves to 42

await Async.from(() => Promise.resolve(42)).run() // resolves to 42
4.1.0

11 months ago

4.0.0

11 months ago

4.2.0

9 months ago

3.0.4

2 years ago

3.0.7

2 years ago

3.0.5

2 years ago

3.0.3

2 years ago

3.0.2

2 years ago

3.0.1

2 years ago

3.0.0

2 years ago

2.2.1

2 years ago

2.2.0

2 years ago

2.2.3

2 years ago

2.2.2

2 years ago

2.2.4

2 years ago

2.1.1

3 years ago

2.1.0

3 years ago

2.0.0

3 years ago

1.8.0

3 years ago

1.7.2

3 years ago

1.7.1

3 years ago

1.7.0

3 years ago

1.6.1

3 years ago

1.6.0

3 years ago

1.5.2

3 years ago

1.5.1

3 years ago

1.5.0

3 years ago

1.4.5

3 years ago

1.4.4

3 years ago

1.4.0

3 years ago

1.3.0

3 years ago

1.2.5

3 years ago

1.2.4

4 years ago

1.2.3

4 years ago

1.2.2

4 years ago

1.2.1

4 years ago

1.2.0

4 years ago

1.1.0

4 years ago

1.0.2

4 years ago

1.0.1

4 years ago

1.0.0

4 years ago