{"id":13709527,"url":"https://github.com/rowtype-yoga/purescript-yoga-om","last_synced_at":"2026-01-18T17:33:57.145Z","repository":{"id":113967674,"uuid":"499055905","full_name":"rowtype-yoga/purescript-yoga-om","owner":"rowtype-yoga","description":null,"archived":false,"fork":false,"pushed_at":"2024-07-26T10:14:05.000Z","size":86,"stargazers_count":12,"open_issues_count":3,"forks_count":2,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-05-06T16:48:02.354Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"PureScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit-0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rowtype-yoga.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-06-02T08:34:28.000Z","updated_at":"2024-11-06T20:29:20.000Z","dependencies_parsed_at":null,"dependency_job_id":"1ef198f2-7c40-4dec-8b33-6f7447b6a8bd","html_url":"https://github.com/rowtype-yoga/purescript-yoga-om","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/rowtype-yoga/purescript-yoga-om","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rowtype-yoga%2Fpurescript-yoga-om","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rowtype-yoga%2Fpurescript-yoga-om/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rowtype-yoga%2Fpurescript-yoga-om/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rowtype-yoga%2Fpurescript-yoga-om/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rowtype-yoga","download_url":"https://codeload.github.com/rowtype-yoga/purescript-yoga-om/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rowtype-yoga%2Fpurescript-yoga-om/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28544926,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-18T14:59:57.589Z","status":"ssl_error","status_checked_at":"2026-01-18T14:59:46.540Z","response_time":98,"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-08-02T23:00:40.873Z","updated_at":"2026-01-18T17:33:57.126Z","avatar_url":"https://github.com/rowtype-yoga.png","language":"PureScript","funding_links":[],"categories":["Data types"],"sub_categories":[],"readme":"# 🕉️ (Om)\n\n\nA powerful general purpose type for writing applications.\n\nFor an extensive overview checkout the [tests](./test/Test/Main.purs).\n\n## Installation\n\n```bash\nspago install yoga-om\n```\n\n## Quickstart\n\nCheck out the [minimal example](#running-an-om)!\n\n## What can it do?\n\nAn `Om` consists of three parts. \nA *context*, potential *errors*, and the *value* of a concurrent computation.\n\nConventionally in code, we abbreviate this as `Om ctx errs a`.\n\n### `ctx`: Dependency injection\n\n`Om` supports writing code that `ask`s for dependencies that you only provide\nonce at the start of the application.\n\n```purescript\nmyOmThatNeedsDbName = do\n  { dbName } \u003c- ask\n```\n\nThis is an `Om` of the shape `Om { dbName :: String } _ _`. We are only \nconcerned about the `ctx` part of `Om` in this section, hence the `_`s.\n\n### `errors`: Mix-and match errors\n\nDealing with failure in `Om` is just wonderful.\n\n### Throwing errors\nTo throw an error, simply use the `throwError` function with a record that \nhas the name of the error as its label and the error data as its value:\n\n```purescript\nmyOmThatThrows = Om.throw { myError: \"This failed\" }\n```\n\nThis is an `Om _ ( myError :: String ) _`\n\n### Handling errors\nTo catch one or multiple errors use `handleErrors`\n\n```purescript\nmyOmHandled = handleErrors { myError: \\text -\u003e Console.warn text } myOmThatThrows\n```\n\nAs stated earlier `myOmThatThrows` has type: `Om _ (myError :: String) _`.\n\nBy handling all potential `myError` errors we've produced `myOmHandled` which has \nthe type `Om _ () _`.\n\n### Combining errors\n\nA powerful feature of `Om` is that you can easily combine different `Om`\ncomputations that can throw different errors.\n\n```purescript\nom1 :: forall otherErrors. Om _ ( ioError :: Int | otherErrors ) _\nom1 = throw { ioError: -8 }\n\nom2 :: forall otherErrors. Om _ ( userError :: String | otherErrors ) _\nom2 = throw { userError: \"Your last name can't be shorter than 0 characters\" }\n\nom3 :: forall errs. Om _ ( ioError :: Int, userError :: String | errs ) _ \nom3 = do \n  om1\n  om2\n```\n\nThis means that you can and should only tag a function with the errors it can actually\nthrow and not the complete set of errors that might happen anywhere in your program.\n\nThe compiler helps you out with this.\n\n### Working with `Aff` and `Effect`\n\nIn order to transform any `Aff a` into an `Om _ _ a` you may use `liftAff`, or `fromAff`.\nTo do the same with `Effect` you may use `liftEffect`.\n\n### Running an `Om`\n\nLet's bring it all back home. Eventually you want to actually run an `Om`.\nMost probably at the start of your application, in a `main :: Effect Unit` function for\nexample.\n\nThat's the right time to supply the dependencies to your `Om` and to handle any remaining possible errors:\n\n```purescript\nmodule Main where\n\nimport Prelude\nimport Node.Process (lookupEnv)\nimport Effect.Class.Console as Console\nimport Effect (Effect)\nimport Data.Maybe (Maybe)\nimport Yoga.Om as Om\nimport Yoga.Om (Om)\n\nmain :: Effect Unit\nmain = do\n  envName \u003c- lookupEnv \"NAME\"\n  greet\n    # Om.launchOm_\n        { envName }\n        { exception:\n            \\e -\u003e Console.error (\"Unexpected exception: \" \u003c\u003e show e)\n        , nameNotFound:\n            \\_ -\u003e Console.error \"Make sure the $NAME env variable is set\"\n        }\n\ngreet :: Om { envName :: Maybe String } (nameNotFound :: Unit) Unit\ngreet = do\n  { envName } \u003c- Om.ask\n  name \u003c- envName # Om.note { nameNotFound: unit }\n  Console.log $ \"Welcome \" \u003c\u003e name\n```\n\n### Parallel computations\n\nYou can run different `Om`s in parallel.\n\nEither the fastest one that does not error out wins:\n```purescript\nOm.race [ Om.delay (1.0 # Seconds) *\u003e pure \"slow\" , pure \"fast\" ]\n```\n\nOr you look at all the results and get an `Om _ _ (Array _)`:\n```purescript\nOm.inParallel\n    [ Om.delay (9.0 # Milliseconds) *\u003e pure \"1\"\n    , Om.delay (1.0 # Milliseconds) *\u003e pure \"2\"\n    ]\n```\n\n## FAQ\n\n### What if I need `State` and `Writer`? \n\nSince `Om` combines the powers of `Reader` and supports `Effect`ful computations\nit is less clutter (especially on the type signature) to bolt this functionality \non ad-hoc via `Ref`s in the `ctx` \n\n\n### It's so tedious to repeat the labels and keys in `ctx` and `errs`\n\nYou will probably prefer to define type aliases:\n\n```purescript\nmodule Main where\n\nimport DB as DB\nimport Cache as Cache\n-- ...\nimport Type.Row (type (+))\n\nmyWholeApp :: Om (DB.Ctx + Cache.Ctx ()) (DB.Errs + Cache.Errs ()) Unit\nmyWholeApp = do\n  DB.writeToDB \"'); DROP TABLE orders;--\"\n\n```\n\n```purescript\nmodule DB where\n\nwriteToDB :: forall ctx errs. String -\u003e Om (Ctx ctx) (Errs errs) Unit\nwriteToDB s = do\n  -- ...\n  pure unit \n\n\ntype Ctx r = (dbCtx :: { port :: Int, hostname :: String } | r)\n\ntype Errs r = IOErr + TimeoutErr + r\ntype IOErr r = ( ioError :: { message :: String, code :: Int, details :: String } | r )\ntype TimeoutErr r = ( timeout :: { query :: String } | r )\n\n```\n\n## Technical behind the scenes info\n\n`Om` is a monad transformer stack built from the stack safe continuation \npassing `RWSET` without `State` or `Writer` with errors specialised to \npolymorphic `Variant`s.\n\n\n# Special Thanks\n\nWe would like to thank all the PureScript contributors, especially the ones whose libraries we depend on.\n\nSpecial thanks to @reactormonk who has a very similar library ([rave](https://github.com/reactormonk/purescript-rave)) which has the trick to inject variants as single field records instead of the cumbersome `(Proxy :: Proxy \"key\") value` syntax.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frowtype-yoga%2Fpurescript-yoga-om","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frowtype-yoga%2Fpurescript-yoga-om","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frowtype-yoga%2Fpurescript-yoga-om/lists"}