{"id":15176409,"url":"https://github.com/moritzploss/do","last_synced_at":"2025-10-26T11:31:31.620Z","repository":{"id":47290365,"uuid":"344739204","full_name":"moritzploss/do","owner":"moritzploss","description":"Haskell-style type classes for Erlang, including monads, applicatives, functors, and traversables","archived":false,"fork":false,"pushed_at":"2024-07-25T08:47:36.000Z","size":98,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-01-31T18:56:53.526Z","etag":null,"topics":["erlang","functors","monads"],"latest_commit_sha":null,"homepage":"","language":"Erlang","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/moritzploss.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":"2021-03-05T08:08:05.000Z","updated_at":"2024-07-25T17:29:25.000Z","dependencies_parsed_at":"2024-07-25T10:13:13.966Z","dependency_job_id":null,"html_url":"https://github.com/moritzploss/do","commit_stats":{"total_commits":33,"total_committers":2,"mean_commits":16.5,"dds":"0.030303030303030276","last_synced_commit":"47a004c94fcb2a07aa713c6c3e53e0a1b1ce503f"},"previous_names":[],"tags_count":30,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/moritzploss%2Fdo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/moritzploss%2Fdo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/moritzploss%2Fdo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/moritzploss%2Fdo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/moritzploss","download_url":"https://codeload.github.com/moritzploss/do/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":238319475,"owners_count":19452343,"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":["erlang","functors","monads"],"created_at":"2024-09-27T13:04:04.507Z","updated_at":"2025-10-26T11:31:26.322Z","avatar_url":"https://github.com/moritzploss.png","language":"Erlang","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Tests](https://github.com/moritzploss/do/actions/workflows/tests.yml/badge.svg)](https://github.com/moritzploss/do/actions/workflows/tests.yml)\n\n## do\n\nThis package brings Haskell-style type classes to Erlang, including\nmonads, applicatives, functors, and traversables. It provides implementations\nof commonly used class instances, as well as useful utility functions.\n\n### Installation\n\nTo install the latest release from [`hex`](https://hex.pm/packages/do), add\n`do` to the `deps` in your rebar3 config file:\n\n    {do, \"2.0.2\"}\n\n### What's in the box\n\nThe `do` package implements [`either`](./src/instances/do_either.erl),\n[`list`](./src/instances/do_list.erl), and\n[`maybe`](./src/instances/do_maybe.erl) monads. For a complete overview\nof types and functions, refer to [`do_types.hrl`](./include/do_types.hrl) and\n[`do`'s docs on hex](https://hexdocs.pm/do/).\n\n### fmap\n\nUse the `?fmap` macro or `do:fmap/2` to map functions over functors:\n\n```erlang\n-include_lib(\"do/include/do.hrl\").\n\nincrement(N) -\u003e\n  N + 1.\n\nfmap_either() -\u003e\n  {ok, 2}         = ?fmap(fun increment/1, {ok, 1}),\n  {error, reason} = ?fmap(fun increment/1, {error, reason}).\n\nfmap_maybe() -\u003e\n  {just, 2} = ?fmap(fun increment/1, {just, 1}),\n  nothing   = ?fmap(fun increment/1, nothing).\n\nfmap_list() -\u003e\n  [2, 3, 4] = ?fmap(fun increment/1, [1, 2, 3]).\n\nfmap_map() -\u003e\n  #{a =\u003e 2} = ?fmap(fun increment/1, #{a =\u003e 1}).\n```\n\n### sequence\n\nUse the `?sequence` macro or `do:sequence/1` to sequence a traversable of\napplicatives. For example:\n\n```erlang\n-include_lib(\"do/include/do.hrl\").\n\nsequence_list() -\u003e\n  {ok, [1, 2, 3]} = ?sequence([{ok, 1}, {ok, 2}, {ok, 3}]),\n  {error, reason} = ?sequence([{ok, 1}, {error, reason}, {ok, 3}]).\n\nsequence_map() -\u003e\n  {just, #{a =\u003e 1, b =\u003e 2}} = ?sequence(#{a =\u003e {just, 1}, b =\u003e {just, 2}}),\n  nothing                   = ?sequence(#{a =\u003e {just, 1}, b =\u003e nothing}).\n\nsequence_either() -\u003e\n  [{ok, 1}] = ?sequence({ok, [1]}),\n  []        = ?sequence({ok, []}).\n\n```\n\n### bind\n\nUse the `?bind` macro or `do:bind/2` to bind (`\u003e\u003e=`) a function that returns a\nmonad to a monad of the same type. In case of the\n[`either`](./src/instances/do_either.erl) monad:\n\n```erlang\n-include_lib(\"do/include/do.hrl\").\n\nincrement_either(N) when is_integer(N) -\u003e\n  {ok, N + 1};\nincrement_either(_) -\u003e\n  {error, no_int}.\n\nbind_either() -\u003e\n  {ok, 2}         = ?bind({ok, 1}, fun increment_either/1),\n  {error, no_int} = ?bind({ok, foo}, fun increment_either/1),\n  {error, reason} = ?bind({error, reason}, fun increment_either/1).\n```\n\nFor the [`maybe`](./src/instances/do_maybe.erl) monad:\n\n```erlang\nincrement_maybe(N) when is_integer(N) -\u003e\n  {just, N + 1};\nincrement_maybe(_) -\u003e\n  nothing.\n\nbind_maybe() -\u003e\n  {just, 2} = ?bind({just, 1}, fun increment_maybe/1),\n  nothing   = ?bind({just, foo}, fun increment_maybe/1),\n  nothing   = ?bind(nothing, fun increment_maybe/1).\n```\n\nFor the [`list`](./src/instances/do_list.erl) monad:\n\n```erlang\nincrement_list(N) when is_integer(N) -\u003e\n  [N + 1];\nincrement_maybe(_) -\u003e\n  [].\n\nbind_list() -\u003e\n  [2] = ?bind([1], fun increment_list/1),\n  []  = ?bind([foo], fun increment_list/1),\n  []  = ?bind([], fun increment_maybe/1).\n```\n\n### then\n\nUse the `?then` macro or `do:then/2` to chain (`\u003e\u003e`) monadic expressions of the\nsame type. The second argument to `?then` is wrapped in a thunk that will only\nbe executed if the first argument indicates success. For example:\n\n```erlang\n-include_lib(\"do/include/do.hrl\").\n\nincrement(N) when is_integer(N) -\u003e\n  [N + 1];\nincrement(_) -\u003e\n  [].\n\nthen_list() -\u003e\n  [2] = ?then([5], increment(1)),\n  []  = ?then([5], increment(foo)),\n  []  = ?then([],  increment(1)).\n```\n\n### liftm\n\nUse the `?liftm` macro to lift a function into a monad. For example:\n\n```erlang\n-include_lib(\"do/include/do.hrl\").\n\nliftm_either() -\u003e\n  {ok, 3}         = ?liftm(fun erlang:'+'/2, {ok, 1}, {ok, 2}),\n  {error, reason} = ?liftm(fun erlang:'+'/2, {ok, 1}, {error, reason}).\n```\n\nArguments to `?liftm` are evaluated lazily. In the following example\n`1 + 1` will never be evaluated:\n\n```erlang\n-include_lib(\"do/include/do.hrl\").\n\nliftm_either() -\u003e\n  {error, reason} = ?liftm(fun erlang:'+'/2, {error, reason}, {ok, 1 + 1}).\n```\n\n### do\n\nUse the `?do` macro or `do:do/2` to consecutively bind (`\u003e\u003e=` or `\u003e\u003e`) monads\nand functions. The macro takes a start value (a monad), and a list of functions.\nThe functions must each take either 0 or 1 argument(s) and must return a monad.\nOn execution, the start value is passed to the first function, and is then\npiped through consecutive functions using `bind` or `then`. For example (with\n[`either`](./src/instances/do_either.erl) monad):\n\n```erlang\n-include_lib(\"do/include/do.hrl\").\n\nincrement(N) when is_integer(N) -\u003e\n  {ok, N + 1};\nincrement(_) -\u003e\n  {error, no_int}.\n\nint_to_bin(N) when is_integer(N) -\u003e\n  {ok, integer_to_binary(N)};\nint_to_bin(_) -\u003e\n  {error, no_int}.\n\ndo_either() -\u003e\n  {ok, 4}         = ?do({ok, 1}, [ fun increment/1,\n                                   fun increment/1,\n                                   fun increment/1 ]),\n\n  {error, no_int} = ?do({ok, 1}, [ fun increment/1,\n                                   fun int_to_bin/1,\n                                   fun increment/1 ]).\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmoritzploss%2Fdo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmoritzploss%2Fdo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmoritzploss%2Fdo/lists"}