All Projects → pelotom → Burrido

pelotom / Burrido

Licence: mit
Do-notation for JavaScript

Programming Languages

javascript
184084 projects - #8 most used programming language

Projects that are alternatives of or similar to Burrido

Functionaljava
Functional programming in Java
Stars: ✭ 1,472 (+881.33%)
Mutual labels:  monad
Alembic
⚗️ Functional JSON Parser - Linux Ready 🐧
Stars: ✭ 115 (-23.33%)
Mutual labels:  monad
Rubico
[a]synchronous functional programming
Stars: ✭ 133 (-11.33%)
Mutual labels:  monad
Nord Sublime Text
An arctic, north-bluish clean and elegant Sublime Text theme.
Stars: ✭ 109 (-27.33%)
Mutual labels:  syntax
Mayre
Maybe render a React component, maybe not 😮
Stars: ✭ 114 (-24%)
Mutual labels:  monad
Syntax
A VSCode dark theme inspired by Framer’s popular code editor.
Stars: ✭ 123 (-18%)
Mutual labels:  syntax
Postcss Less
PostCSS Syntax for parsing LESS
Stars: ✭ 93 (-38%)
Mutual labels:  syntax
Ecsharp
Home of LoycCore, the LES language of Loyc trees, the Enhanced C# parser, the LeMP macro preprocessor, and the LLLPG parser generator.
Stars: ✭ 141 (-6%)
Mutual labels:  syntax
Dunai
Classic and Arrowized Functional Reactive Programming, Reactive Programming, and Stream programming, all via Monadic Stream Functions
Stars: ✭ 115 (-23.33%)
Mutual labels:  monad
Play Monadic Actions
A simple scala DSL to allow clean and monadic style for Play! Actions
Stars: ✭ 129 (-14%)
Mutual labels:  monad
Masala Parser
Javascript Generalized Parser Combinators
Stars: ✭ 110 (-26.67%)
Mutual labels:  monad
Expected
What did you expect?
Stars: ✭ 113 (-24.67%)
Mutual labels:  monad
Sugar Rs
Rust syntax sugar collections.
Stars: ✭ 125 (-16.67%)
Mutual labels:  syntax
Crocks
A collection of well known Algebraic Data Types for your utter enjoyment.
Stars: ✭ 1,501 (+900.67%)
Mutual labels:  monad
Functional Promises
Write code like a story w/ a powerful Fluent (function chaining) API
Stars: ✭ 141 (-6%)
Mutual labels:  monad
Cats Stm
An STM implementation for Cats Effect
Stars: ✭ 106 (-29.33%)
Mutual labels:  monad
Clang Format Hooks
Apply a coding style with clang-format only to new code added to an existing code base.
Stars: ✭ 122 (-18.67%)
Mutual labels:  syntax
Udify
A single model that parses Universal Dependencies across 75 languages. Given a sentence, jointly predicts part-of-speech tags, morphology tags, lemmas, and dependency trees.
Stars: ✭ 147 (-2%)
Mutual labels:  syntax
Lightscript
JavaScript, with cleaned-up syntax and a few conveniences.
Stars: ✭ 141 (-6%)
Mutual labels:  syntax
Es.next.syntax.vim
ES.Next syntax for Vim
Stars: ✭ 125 (-16.67%)
Mutual labels:  syntax

burrido Build Status

An experiment in bringing Haskell's programmable semicolon to JavaScript, using generators.

Installation

npm install --save burrido

Usage

import Monad from 'burrido'

const ArrayMonad = Monad({
  pure: x => [x],
  bind: (xs, f) => xs.map(f).reduce((a, b) => a.concat(b), [])
})

ArrayMonad.Do(function*() {
  const x = yield [1,2]
  const y = yield [3,4]
  return x * y
}) // -> [3,4,6,8]

The above should look fairly self-explanatory to a Haskell programmer: we are declaring a Monad instance for arrays, which requires us to define two functions: pure and bind. Then we obtain a special function Do which is a do-notation tailored to that particular monad. We pass a generator function to Do, within which we gain access to the yield keyword, allowing us to "unwrap" monadic values and release their effects.

In fact this is a bit more versatile than Haskell's do-notation in a couple of interesting ways:

  1. Haskell's Monad is a type class, which means that there can only be one way in which a given type constructor is considered a monad within a given scope. But some type constructors can be considered monadic in more than one way (e.g. Either). By contrast, here you can create as many Monad definitions as you want for a particular type (constructor), and each just has its own special Do function.
  2. While
const foo = yield bar

is comparable to

foo <- bar

in do-notation, one can also create compound yield expressions which have no direct analogue in Haskell. For example,

const foo = yield (yield bar)

would have to be written as

foo' <- bar
foo <- foo'

in do-notation. In the context of Do blocks, yield serves a similar purpose to the ! operator in both Idris and the Effectful library for Scala.

An example using RxJS

RxJS Observables form a monad in several different ways:

const { just: pure } = Observable

const { Do: doConcat } = Monad({
  pure,
  bind: (x, f) => x.concatMap(f)
})

const { Do: doMerge } = Monad({
  pure,
  bind: (x, f) => x.flatMap(f)
})

const { Do: doLatest } = Monad({
  pure,
  bind: (x, f) => x.flatMapLatest(f)
})

It's instructive to see what happens when you apply these different do-notations to the same generator block:

const { from } = Observable

const block = function*() {
  // for each x in [1,2,3]...
  const x = yield from([1,2,3])
  // wait 1 second
  yield pure({}).delay(1000)
  // then return the value
  return x
}

// Prints 1, 2, and 3 separated by 1 second intervals
doConcat(block).subscribe(console.log)
// Waits 1 second and then prints 1, 2, 3 all at once
doMerge(block).subscribe(console.log)
// Waits 1 second and then prints 3
doLatest(block).subscribe(console.log)

This should make sense if you think about the semantics of each of these different methods of "flattening" nested Observables. Each do* flavor applies its own semantics to the provided block, but they all return Observables, so we can freely combine them:

doConcat(function*() {
  const x = yield doConcat(function*() {
          //...
        }),
        y = yield doMerge(function*() {
          //...
        }),
        z = yield doLatest(function*() {
          //...
        })
  return { x, y, z }
})

RxJS has a function spawn which allows you to use this kind of syntax with Observables, but it only works properly with single-valued streams (essentially Promises), whereas burrido allows manipulating streams of multiple values, using multiple different semantics.

Caveats

Because JavaScript's generators are neither immutable nor cloneable, we are forced to simulate immutable generators using a library called immutagen. There are two unavoidable downsides to this approach:

  • pure and bind must be side-effect free. This can always be achieved in practice by making the monadic type lazy (wrapping it in a closure). See this issue.
  • The simulation is inefficient, requiring O(n^2) steps to execute the nth yield within a single generator. See this issue.

With natively immutable generators (or the native ability to clone mutable generators), both of these limitations would go away.

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