{"id":17056980,"url":"https://github.com/pelotom/burrido","last_synced_at":"2025-07-02T01:31:20.911Z","repository":{"id":57191738,"uuid":"59379672","full_name":"pelotom/burrido","owner":"pelotom","description":"Do-notation for JavaScript","archived":false,"fork":false,"pushed_at":"2017-04-19T18:08:09.000Z","size":17,"stargazers_count":178,"open_issues_count":1,"forks_count":2,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-06-03T18:52:27.120Z","etag":null,"topics":["monad","notation","syntax"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pelotom.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-05-21T20:14:33.000Z","updated_at":"2025-01-27T12:03:30.000Z","dependencies_parsed_at":"2022-09-01T03:22:44.362Z","dependency_job_id":null,"html_url":"https://github.com/pelotom/burrido","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/pelotom/burrido","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pelotom%2Fburrido","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pelotom%2Fburrido/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pelotom%2Fburrido/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pelotom%2Fburrido/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pelotom","download_url":"https://codeload.github.com/pelotom/burrido/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pelotom%2Fburrido/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":263059598,"owners_count":23407382,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["monad","notation","syntax"],"created_at":"2024-10-14T10:26:09.779Z","updated_at":"2025-07-02T01:31:20.886Z","avatar_url":"https://github.com/pelotom.png","language":"JavaScript","funding_links":[],"categories":["Libraries"],"sub_categories":["[Javascript](https://developer.mozilla.org/en-US/docs/Web/JavaScript)"],"readme":"# burrido [![Build Status](https://travis-ci.org/pelotom/burrido.svg?branch=master)](https://travis-ci.org/pelotom/burrido)\n\nAn experiment in bringing Haskell's [programmable semicolon](https://en.wikibooks.org/wiki/Haskell/do_notation) to JavaScript, using [generators](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator).\n\n## Installation\n\n```\nnpm install --save burrido\n```\n\n## Usage\n\n```javascript\nimport Monad from 'burrido'\n\nconst ArrayMonad = Monad({\n  pure: x =\u003e [x],\n  bind: (xs, f) =\u003e xs.map(f).reduce((a, b) =\u003e a.concat(b), [])\n})\n\nArrayMonad.Do(function*() {\n  const x = yield [1,2]\n  const y = yield [3,4]\n  return x * y\n}) // -\u003e [3,4,6,8]\n```\n\nThe 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](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*) to `Do`, within which we gain access to the `yield` keyword, allowing us to \"unwrap\" monadic values and release their effects.\n\nIn fact this is a bit more versatile than Haskell's *do*-notation in a couple of interesting ways:\n  1. Haskell's `Monad` is a [type class](https://www.haskell.org/tutorial/classes.html), 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.\n  1. While\n  ```javascript\n  const foo = yield bar\n  ```\n\n  is comparable to\n  ```haskell\n  foo \u003c- bar\n  ```\n\n  in *do*-notation, one can also create compound `yield` expressions which have no direct analogue in Haskell. For example,\n  ```javascript\n  const foo = yield (yield bar)\n  ```\n\n  would have to be written as\n  ```haskell\n  foo' \u003c- bar\n  foo \u003c- foo'\n  ```\n\n  in *do*-notation. In the context of `Do` blocks, `yield` serves a similar purpose to the `!` operator in both [Idris](http://www.idris-lang.org/) and the [Effectful](https://github.com/pelotom/effectful) library for Scala.\n\n## An example using [RxJS](https://github.com/Reactive-Extensions/RxJS)\n\nRxJS `Observable`s form a monad in several different ways:\n\n```javascript\nconst { just: pure } = Observable\n\nconst { Do: doConcat } = Monad({\n  pure,\n  bind: (x, f) =\u003e x.concatMap(f)\n})\n\nconst { Do: doMerge } = Monad({\n  pure,\n  bind: (x, f) =\u003e x.flatMap(f)\n})\n\nconst { Do: doLatest } = Monad({\n  pure,\n  bind: (x, f) =\u003e x.flatMapLatest(f)\n})\n```\n\nIt's instructive to see what happens when you apply these different *do*-notations to the same generator block:\n\n```javascript\nconst { from } = Observable\n\nconst block = function*() {\n  // for each x in [1,2,3]...\n  const x = yield from([1,2,3])\n  // wait 1 second\n  yield pure({}).delay(1000)\n  // then return the value\n  return x\n}\n\n// Prints 1, 2, and 3 separated by 1 second intervals\ndoConcat(block).subscribe(console.log)\n// Waits 1 second and then prints 1, 2, 3 all at once\ndoMerge(block).subscribe(console.log)\n// Waits 1 second and then prints 3\ndoLatest(block).subscribe(console.log)\n```\n\nThis should make sense if you think about the semantics of each of these different methods of \"flattening\" nested `Observable`s. Each `do*` flavor applies its own semantics to the provided block, but they all return `Observable`s, so we can freely combine them:\n\n```javascript\ndoConcat(function*() {\n  const x = yield doConcat(function*() {\n          //...\n        }),\n        y = yield doMerge(function*() {\n          //...\n        }),\n        z = yield doLatest(function*() {\n          //...\n        })\n  return { x, y, z }\n})\n```\n\nRxJS has a function [`spawn`](https://github.com/Reactive-Extensions/RxJS/blob/master/doc/api/core/operators/spawn.md) which allows you to use this kind of syntax with `Observable`s, but it only works properly with single-valued streams (essentially Promises), whereas burrido allows manipulating streams of multiple values, using multiple different semantics.\n\n## Caveats\n\nBecause JavaScript's generators are neither immutable nor cloneable, we are forced to simulate immutable generators using a library called [immutagen](https://github.com/pelotom/immutagen). There are two unavoidable downsides to this approach:\n- `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](https://github.com/pelotom/burrido/issues/1).\n- The simulation is inefficient, requiring *O(n^2)* steps to execute the *nth* yield within a single generator. See [this issue](https://github.com/pelotom/burrido/issues/2).\n\nWith natively immutable generators (or the native ability to clone mutable generators), both of these limitations would go away.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpelotom%2Fburrido","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpelotom%2Fburrido","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpelotom%2Fburrido/lists"}