{"id":13484759,"url":"https://github.com/hadronized/do-notation","last_synced_at":"2025-12-12T15:14:18.209Z","repository":{"id":45172646,"uuid":"254703313","full_name":"hadronized/do-notation","owner":"hadronized","description":"The Haskell’s do notation brought to Rust","archived":false,"fork":false,"pushed_at":"2022-01-03T22:05:48.000Z","size":23,"stargazers_count":55,"open_issues_count":2,"forks_count":2,"subscribers_count":5,"default_branch":"master","last_synced_at":"2024-10-30T18:42:51.613Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/hadronized.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-04-10T18:09:30.000Z","updated_at":"2024-10-29T16:36:47.000Z","dependencies_parsed_at":"2022-09-01T05:02:05.056Z","dependency_job_id":null,"html_url":"https://github.com/hadronized/do-notation","commit_stats":null,"previous_names":["hadronized/do-notation","phaazon/do-notation"],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hadronized%2Fdo-notation","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hadronized%2Fdo-notation/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hadronized%2Fdo-notation/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hadronized%2Fdo-notation/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hadronized","download_url":"https://codeload.github.com/hadronized/do-notation/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225633224,"owners_count":17499932,"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-07-31T17:01:32.741Z","updated_at":"2025-12-12T15:14:18.129Z","avatar_url":"https://github.com/hadronized.png","language":"Rust","funding_links":[],"categories":["Rust"],"sub_categories":[],"readme":"\u003c!-- cargo-sync-readme start --\u003e\n\n# `do-notation`, the monadic `do` notation brought to Rust.\n\nThis crate provides the `m!` macro, which provides the Haskell monadic syntactic sugar `do`.\n\n\u003e Note: it is not possible to use the `do!` syntax as `do` is a reserved keyword in Rust.\n\nThe syntax is very similar to what you find in Haskell:\n\n- You use the `m!` macro; in Haskell, you use the `do` keyword.\n- The `\u003c-` syntactic sugar binds its left hand side to the monadic right hand side\n  by _entering_ the right side via a closure.\n- Like almost any statement in Rust, you must end your statement with a semicolon (`;`).\n- The last line must be absent of `;` or contains the `return` keyword.\n- You can use `return` nowhere but on the last line.\n- A line containing a single expression with a semicolon is a valid statement and has the same effect as `_ \u003c- expr`.\n- `let` bindings are allowed in the form `let \u003cpattern\u003e = \u003cexpr\u003e;` and have the regular Rust meaning.\n- The `do` notation syntax does not extend into inner code blocks; however, it can have its own `m!` block. For example:\n  `m! { outer_do... if exp { m! { inner_do... } } else { ... } ... }`.\n\n## How do I make my monad works with `m!`?\n\nBecause monads are higher-kinded types, it is not possible to define the monadic do-notation in a fully type-system\nelegant way. However, this crate is based on the rebindable concept in Haskell (i.e. you can change what the `\u003e\u003e=`\noperator’s types are), so `m!` has one type-system requirement and one syntactic requirement.\n\nFirst, you have to implement one trait: [`Lift`], which allows to _lift_ a value `A` into a _monadic structure of\n`A`_. For instance, lifting a `A` into the `Option` monad yields an `Option\u003cA\u003e`.\n\nThen, you have to provide an `and_then` method, which is akin to Haskell’s `\u003e\u003e=` operator. The choice of using\n`and_then` and not a proper name like `flat_map` or `bind` is due to the current state of the standard-library —\nmonads like `Option` and `Result\u003c_, E\u003e` don’t have `flat_map` defined on them but have `and_then`. The type signature\nis not enforced, but:\n\n- `and_then` must be a binary function taking a type `A`, a closure `A -\u003e Monad\u003cB\u003e` and returns `Monad\u003cB\u003e`, where\n  `Monad` is the monad you are adding `and_then` for. For instance, if you are implementing it for `Option`,\n  `and_then` takes an `A`, a closure `A -\u003e Option\u003cB\u003e` and returns an `Option\u003cB\u003e`.\n- `and_then` must move its first argument, which has to be `self`. The type of `Self` is not enforced.\n- `and_then`’s closure must take `A` with a `FnOnce` closure.\n\n## Meaning of the `\u003c-` operator\n\nThe `\u003c-` syntactic sugar is not strictly speaking an operator: it’s not valid vanilla Rust. Instead, it’s a trick\ndefined in the `m!` allowing to use both [`Lift::lift`] and `and_then`. When you look at code inside a do-notation\nblock, every monadic statements (separated with `;` in this crate) can be imagined as a new level of nesting inside\na closure — the one passed to `and_then`, indeed.\n\n## First example: fallible code\n\nOne of the first monadic application that people learn is the _fallible_ effect — `Maybe` in Haskell.\nIn `Rust`, it’s `Option`. `Option` is an interesting monad as it allows you to fail early.\n\n```rust\nuse do_notation::m;\n\nlet r = m! {\n  x \u003c- Some(\"Hello, world!\");\n  y \u003c- Some(3);\n  Some(x.len() * y)\n};\n\nassert_eq!(r, Some(39));\n```\n\nThe `binding \u003c- expr` syntax unwraps the right part and binds it to `binding`, making it available to\nnext calls — remember, nested closures. The final line re-enters the structure (here, `Option`) explicitly.\n\nNote that it is possible to re-enter the structure without having to specify how / knowing the structure\n(with `Option`, you re-enter with `Some`). You can use the `return` keyword, that will automatically lift the\nvalue into the right structure:\n\n```rust\nuse do_notation::m;\n\nlet r = m! {\n  x \u003c- Some(1);\n  y \u003c- Some(2);\n  z \u003c- Some(3);\n  return [x, y, z];\n};\n\nassert_eq!(r, Some([1, 2, 3]));\n```\n\n\u003c!-- cargo-sync-readme end --\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhadronized%2Fdo-notation","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhadronized%2Fdo-notation","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhadronized%2Fdo-notation/lists"}