{"id":13396974,"url":"https://github.com/purescript-contrib/purescript-coroutines","last_synced_at":"2026-03-12T14:20:06.004Z","repository":{"id":1089889,"uuid":"39913169","full_name":"purescript-contrib/purescript-coroutines","owner":"purescript-contrib","description":"Computations which can suspend their execution and return control to their invoker","archived":false,"fork":false,"pushed_at":"2022-10-27T17:18:46.000Z","size":123,"stargazers_count":36,"open_issues_count":4,"forks_count":10,"subscribers_count":5,"default_branch":"main","last_synced_at":"2026-02-15T14:24:27.751Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"PureScript","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/purescript-contrib.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-07-29T19:53:22.000Z","updated_at":"2025-08-20T13:19:22.000Z","dependencies_parsed_at":"2022-08-07T03:00:02.515Z","dependency_job_id":null,"html_url":"https://github.com/purescript-contrib/purescript-coroutines","commit_stats":null,"previous_names":["paf31/purescript-coroutines"],"tags_count":24,"template":false,"template_full_name":null,"purl":"pkg:github/purescript-contrib/purescript-coroutines","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/purescript-contrib%2Fpurescript-coroutines","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/purescript-contrib%2Fpurescript-coroutines/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/purescript-contrib%2Fpurescript-coroutines/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/purescript-contrib%2Fpurescript-coroutines/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/purescript-contrib","download_url":"https://codeload.github.com/purescript-contrib/purescript-coroutines/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/purescript-contrib%2Fpurescript-coroutines/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30428054,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-12T14:00:25.264Z","status":"ssl_error","status_checked_at":"2026-03-12T13:59:52.690Z","response_time":114,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":[],"created_at":"2024-07-30T18:01:08.626Z","updated_at":"2026-03-12T14:20:05.952Z","avatar_url":"https://github.com/purescript-contrib.png","language":"PureScript","funding_links":[],"categories":["Async"],"sub_categories":[],"readme":"# Coroutines\n\n[![CI](https://github.com/purescript-contrib/purescript-coroutines/workflows/CI/badge.svg?branch=main)](https://github.com/purescript-contrib/purescript-coroutines/actions?query=workflow%3ACI+branch%3Amain)\n[![Release](https://img.shields.io/github/release/purescript-contrib/purescript-coroutines.svg)](https://github.com/purescript-contrib/purescript-coroutines/releases)\n[![Pursuit](https://pursuit.purescript.org/packages/purescript-coroutines/badge)](https://pursuit.purescript.org/packages/purescript-coroutines)\n[![Maintainer: garyb](https://img.shields.io/badge/maintainer-garyb-teal.svg)](https://github.com/garyb)\n\nCoroutines are a general control structure allowing flow control to pass cooperatively between two different routines. Coroutines in this library are computations which can suspend their execution and return control to their invoker, which can resume the computation. Coroutines can be used to implement pipelines as described in [Coroutine Pipelines by Mario Blažević](https://themonadreader.files.wordpress.com/2011/10/issue19.pdf).\n\nIf you are creating asynchronous or concurrent pipelines you may be interested in:\n\n- [aff-coroutines](https://github.com/purescript-contrib/purescript-aff-coroutines)\n\nIf you need a featureful streaming library, you may also be interested in:\n\n- [pipes](https://github.com/felixSchl/purescript-pipes)\n- [run-streaming](https://github.com/natefaubion/purescript-run-streaming)\n- [machines](https://github.com/purescript-contrib/purescript-machines)\n\nIf you are looking for a FRP library, then you may be interested in:\n\n- [event](https://github.com/paf31/purescript-event)\n\n## Installation\n\nInstall `coroutines` with [Spago](https://github.com/purescript/spago):\n\n```sh\nspago install coroutines\n```\n\n## Quick start\n\nThis quick start briefly introduces the basics of `coroutines`. For a more thorough, beginner-friendly introduction to the library, please see the [library documentation](./docs).\n\nThe basic building block of `coroutines` is the coroutine type `Co`, which exhibits different behavior when it suspensd based on a functor `f`:\n\n- When `f` is the `Emit o` functor, the coroutine emits an output of type `o` and is a `Producer`\n- When `f` is the `Await i` functor, the coroutine waits for an input of type `i` and is a `Consumer`\n- When `f` is the `Transform i o` functor, the coroutine waits for an input of type `i`, and emits an output of type `o`, and is a `Transformer`.\n\nA coroutine which _emits_ can be thought of as a generator, where each yield produces a value. A coroutine which _awaits_ can be thought of as an iteratee, where each yield demands a value. And a coroutine which _transforms_ does both: it demands an input, and produces an output.\n\nUsing these three building blocks we can create some standard coroutines and form them into pipelines.\n\nHere is a coroutine which generates natural numbers:\n\n```purs\nnats :: forall m. (Monad m) =\u003e Producer Int m Unit\nnats = go 0\n  where\n  go i = do\n    emit i\n    go (i + 1)\n```\n\nThe computation runs, emits a number, and suspends; when resumed it will emit the next number and then suspend again. It uses the `emit` function:\n\n```purs\nemit :: forall m o. Monad m =\u003e o -\u003e Producer o m Unit\n```\n\nHere is a coroutine which accepts and prints strings:\n\n```purs\nprinter :: forall a. Consumer String (Aff _) Unit\nprinter = forever do\n  s \u003c- await\n  lift (log s)\n```\n\nThe computation suspends, awaiting a number. When it receives a number it logs the number and then suspends, awaiting a new number. It uses the `await` function:\n\n```purs\nawait :: forall m i. Monad m =\u003e Consumer i m i\n```\n\nHere is a coroutine which transforms inputs by showing them as strings:\n\n```purs\nshowing :: forall a m. (Show a, Monad m) =\u003e Transformer a String m Unit\nshowing = forever (transform show)\n```\n\nThe computation suspends, awaiting an `a`. When it receives the awaited value, it transforms it into a string, emits the new value, and suspends again, awaiting another `a`. It uses the `transform` function:\n\n```purs\ntransform :: forall m i o. Monad m =\u003e (i -\u003e o) -\u003e Transformer i o m Unit\n```\n\nThese coroutines can be combined together using a handful of operators, the most common of which include:\n\n```purs\nconnect :: forall o f m a. MonadRec m =\u003e Parallel f m =\u003e Producer o m a -\u003e Consumer o m a -\u003e Process m a\ninfixr 2 connect as $$\n\ntransformProducer :: forall i o f m a. MonadRec m =\u003e Parallel f m =\u003e Producer i m a -\u003e Transformer i o m a -\u003e Producer o m a\ninfixr 2 transformProducer as $~\n\ntransformConsumer :: forall i o f m a. MonadRec m =\u003e Parallel f m =\u003e Transformer i o m a -\u003e Consumer o m a -\u003e Consumer i m a\ninfixr 2 transformConsumer as ~$\n\ncomposeTransformers :: forall i j k f m a. MonadRec m =\u003e Parallel f m =\u003e Transformer i j m a -\u003e Transformer j k m a -\u003e Transformer i k m a\ninfixr 2 composeTransformers as ~~\n```\n\nOnce composed, the resulting computation can be run using `runFreeT`. If you have used `connect` to connect a producer and consumer, then you can use `runProcess` (a helper function for running a producer/consumer pair via `runFreeT`).\n\nThis example transforms the `nats` producer so that instead of producing integers it produces strings, and then connects the resulting producer to the `printer` consumer. Once connect, we can use `runProcess` to run the pipeline:\n\n```purs\nmain = launchAff $ runProcess ((nats $~ showing) $$ printer)\n```\n\nThe producer will emit a value, then yield; this value will satisfy the `await` call in the consumer, which will use the value and then yield back to the producer. This process will continue indefinitely.\n\n## Documentation\n\n`coroutines` documentation is stored in a few places:\n\n1. Module documentation is [published on Pursuit](https://pursuit.purescript.org/packages/purescript-coroutines).\n2. Written documentation is kept in the [docs directory](./docs).\n3. Usage examples can be found in [the test suite](./test).\n\nIf you get stuck, there are several ways to get help:\n\n- [Open an issue](https://github.com/purescript-contrib/purescript-coroutines/issues) if you have encountered a bug or problem.\n- Ask general questions on the [PureScript Discourse](https://discourse.purescript.org) forum or the [PureScript Discord](https://purescript.org/chat) chat.\n\n## Contributing\n\nYou can contribute to `coroutines` in several ways:\n\n1. If you encounter a problem or have a question, please [open an issue](https://github.com/purescript-contrib/purescript-coroutines/issues). We'll do our best to work with you to resolve or answer it.\n\n2. If you would like to contribute code, tests, or documentation, please [read the contributor guide](./CONTRIBUTING.md). It's a short, helpful introduction to contributing to this library, including development instructions.\n\n3. If you have written a library, tutorial, guide, or other resource based on this package, please share it on the [PureScript Discourse](https://discourse.purescript.org)! Writing libraries and learning resources are a great way to help this library succeed.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpurescript-contrib%2Fpurescript-coroutines","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpurescript-contrib%2Fpurescript-coroutines","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpurescript-contrib%2Fpurescript-coroutines/lists"}