{"id":16313972,"url":"https://github.com/lysxia/bluefin-algae","last_synced_at":"2025-07-24T10:11:10.409Z","repository":{"id":236302490,"uuid":"792338850","full_name":"Lysxia/bluefin-algae","owner":"Lysxia","description":"Algebraic effects in the Bluefin effect system","archived":false,"fork":false,"pushed_at":"2024-05-04T18:01:23.000Z","size":124,"stargazers_count":13,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-10-11T21:52:51.501Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Haskell","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/Lysxia.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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":"2024-04-26T13:17:30.000Z","updated_at":"2024-07-12T20:53:11.000Z","dependencies_parsed_at":"2024-05-03T00:41:53.297Z","dependency_job_id":"62726ea0-8b91-485e-8c88-4b620274fc6a","html_url":"https://github.com/Lysxia/bluefin-algae","commit_stats":null,"previous_names":["lysxia/bluefin-algae"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Lysxia%2Fbluefin-algae","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Lysxia%2Fbluefin-algae/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Lysxia%2Fbluefin-algae/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Lysxia%2Fbluefin-algae/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Lysxia","download_url":"https://codeload.github.com/Lysxia/bluefin-algae/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":221839369,"owners_count":16889609,"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":[],"created_at":"2024-10-10T21:52:48.914Z","updated_at":"2024-10-28T14:19:49.027Z","avatar_url":"https://github.com/Lysxia.png","language":"Haskell","funding_links":[],"categories":[],"sub_categories":[],"readme":"Named algebraic effect handlers in Bluefin\n==========================================\n\nThis package leverages the delimited continuations primitives added in\nGHC 9.6 to implement algebraic effects in the Bluefin effect system.\n\nAlgebraic effects are a minimalistic basis for **user-defined effects**.\nUsing algebraic effects, we can reimplement, from scratch, effects that\nwere built-in the Bluefin library, and more.\n\nThis is an experimental project. There are surprising performance\ncharacteristics which may be problematic for practical applications.\n[Details down below.](#quadratic-behavior-of-non-tail-recursion)\n\n## Free monads in `IO`\n\nAn algebraic effect library is basically a free monad library with support for\nextensible effects.\n\nEffect handlers—the core primitive of algebraic effects—are conceptually\nfolds of trees, aka.\n[`iter` in free](https://hackage.haskell.org/package/free-5.2/docs/Control-Monad-Free.html)\nor [`cata` in recursion-schemes](https://hackage.haskell.org/package/recursion-schemes-5.2.2.5/docs/Data-Functor-Foldable.html#v:cata).\n\nEffect systems—such as Bluefin—enable combinations of effects within a\nsingle parameterized monad. Bluefin Algae seamlessly integrates with Bluefin's\ninfrastructure in order to compose algebraic effects.\n\nThe main novelties in Bluefin Algae are:\n\n- computations use the same representation as `IO` (`State# s -\u003e (# State# s, a #)`)\n  instead of recursive types or continuation-passing encodings.\n  This is possible thanks to the recently available primitives for delimited\n  continuations.\n\n- thanks to Bluefin, effects are statically scoped: performing an operation\n  requires a handle which identifies a specific handler.\n\n  This enables new forms of abstraction boundaries.\n  A function `Eff s a -\u003e Eff s a` cannot handle the operations of its argument.\n  The argument must be explicitly parameterized by the handler to allow\n  handling by its caller: `(forall z. Handler f z -\u003e Eff (z : s) a) -\u003e Eff s a`.\n\n## Highlights\n\n### Concurrency\n\nIn the following example, two threads yield a string back and forth, appending\na suffix every time.\n\n```haskell\nimport Bluefin.Algae.Coroutine\n\npingpong :: Eff ss String\npingpong = withCoroutine coThread mainThread\n  where\n    coThread z0 h = do\n      z1 \u003c- yield h (z0 ++ \"pong\")\n      z2 \u003c- yield h (z1 ++ \"dong\")\n      yield h (z2 ++ \"bong\")\n    mainThread h = do\n      s1 \u003c- yield h \"ping\"\n      s2 \u003c- yield h (s1 ++ \"ding\")\n      s3 \u003c- yield h (s2 ++ \"bing\")\n      pure s3\n\n-- runPureEff pingpong == \"pingpongdingdongbingbong\"\n```\n\nNote that `coThread` and `mainThread` are just `IO` computations under the hood.\nAnd we can interleave their executions without native multithreading. This is the\npower of delimited continuations.\n\n### Nondeterminism\n\nWith the ability to interrupt and resume operations freely, we can do\nbacktracking search in the `Eff` monad.\n\n```haskell\nimport Bluefin.Algae.NonDeterminism as NonDet\n\npythagoras :: z :\u003e zz =\u003e Handler Choice z -\u003e Eff zz (Int, Int, Int)\npythagoras choice = do\n  x \u003c- pick choice [1 .. 10]\n  y \u003c- pick choice [1 .. 10]\n  z \u003c- pick choice [1 .. 10]\n  assume choice (x .^ 2 + y .^ 2 == z .^ 2)\n  pure (x, y, z)\n\n  where (.^) = (Prelude.^) :: Int -\u003e Int -\u003e Int\n\n-- runPureEff (NonDet.toList pythagoras) == [(3,4,5),(4,3,5),(6,8,10),(8,6,10)]\n```\n\n#### Backtracking and state\n\nResuming continuations more than once exposes the impurity of the\nimplementation of the built-in state effect in `Bluefin.State`.\nHere is a program using nondeterminism and state. There are two branches\n(`choose`), both modify the state (`incr`).\n\n```haskell\nimport qualified Bluefin.State as B\n\nnsExampleB :: [Int]\nnsExampleB = runPureEff $ NonDet.toList \\choice -\u003e\n  snd \u003c$\u003e B.runState 0 \\state -\u003e do\n    _ \u003c- choose choice True False\n    B.modify (+ 1) state\n\n-- nsExampleB == [1,2]\n```\n\nThe state handler (`runState`) is under the nondeterminism handler\n(`NonDet.toList`), which suggests a state-passing interpetation, where the\noriginal state is restored upon backtracking (both branches return `1`):\n\n```haskell\nnsExamplePure :: [Int]\nnsExamplePure = runPureEff $ NonDet.toList \\choice -\u003e\n  let state = 0                  -- initial state that was passed to runState\n  _ \u003c- choose choice True False\n  let state' = state + 1         -- modify (+ 1)\n  pure state'                    -- (snd \u003c$\u003e runState) returns the final state\n\n-- nsExamplePure == [1,1]\n```\n\nBecause `Bluefin.State` is backed by `IORef`, the mutation persists\nthrough backtracking (the second branch returns `2` in the first example).\n\nIn comparison, the state effect defined using algebraic effects\n(`Bluefin.Algae.State`) has the state-passing semantics.\n\n```haskell\nimport qualified Bluefin.Algae.State as A\n\nnsExampleA :: [Int]\nnsExampleA = runPureEff $ NonDet.toList \\choice -\u003e\n  A.execState 0 \\state -\u003e do\n    _ \u003c- choose choice True False\n    A.modify (+ 1) state\n\n-- nsExampleA == [1,1]\n```\n\n### Truly scoped exceptions.\n\nThe scoped exceptions from `Bluefin.Exception` are not completely scoped because\nthey can be observed by `bracket`. That is probably the right behavior in practice,\nbut makes the semantics of Bluefin less clear. For the sake of science,\n`Bluefin.Algae.Exception` provides truly scoped exceptions, and implements\n\"`bracket`-observable\" scoped exceptions on top.\n\n## Lowlights\n\n### Quadratic behavior of non-tail recursion.\n\nFor example, the following recursive counter will take time quadratic in `n`\nbecause every call of `modify` traverses the call stack to find its handler\nand capture the continuation.\n\n```haskell\nleftRecCounter :: z :\u003e zz =\u003e Handler (State Int) z -\u003e Int -\u003e Eff zz ()\nleftRecCounter _state 0 = pure ()\nleftRecCounter state n = do\n  leftRecCounter state (n - 1)\n  modify state (+ 1)\n```\n\n## Comparison\n\n### Bluefin\n\nThe Bluefin effect system provides a well-scoped [handle pattern][handle].\nUnlike algebraic effects with which other computational effects can be\nuser-defined, Bluefin provides a collection of built-in effects\n(state, exceptions, coroutines).\n\nWithout delimited continuations, only tail-resumptive algebraic effect handlers\nare expressible in Bluefin. Those are effect handlers restricted to the\nfollowing form, which is equivalent to type `forall r. f r -\u003e Eff ss r`.\n\n```haskell\n(\\e k -\u003e _ \u003e\u003e= k)\n  :: forall r. f r -\u003e (r -\u003e Eff ss a) -\u003e Eff ss a\n```\n\n[handle]: https://jaspervdj.be/posts/2018-03-08-handle-pattern.html\n\n## More reading\n\nNamed effect handlers are described in the literature in:\n\n- [Binders by day, labels by night](https://maciejpirog.github.io/papers/binders-labels.pdf)\n    by Dariusz Biernacki et al.\n- [First-class names for effect handlers](https://www.microsoft.com/en-us/research/uploads/prod/2021/05/namedh-tr.pdf)\n    by Ningning Xie et al. (impemented in the [Koka](https://koka-lang.github.io/koka/doc/index.html) language)\n- [Effects, capabilities, and Boxes](https://dl.acm.org/doi/pdf/10.1145/3527320)\n    by Jonathan Brachtäuser et al.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flysxia%2Fbluefin-algae","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flysxia%2Fbluefin-algae","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flysxia%2Fbluefin-algae/lists"}