{"id":15035732,"url":"https://github.com/witchcrafters/witchcraft","last_synced_at":"2025-10-05T07:47:28.330Z","repository":{"id":2147901,"uuid":"43778196","full_name":"witchcrafters/witchcraft","owner":"witchcrafters","description":"Monads and other dark magic for Elixir","archived":false,"fork":false,"pushed_at":"2023-08-28T14:32:22.000Z","size":6732,"stargazers_count":1215,"open_issues_count":24,"forks_count":61,"subscribers_count":28,"default_branch":"main","last_synced_at":"2025-09-29T12:07:40.388Z","etag":null,"topics":["algebra","algebraic-data-types","applicative","category","elixir","functor","monad","operators","traversable","type-class"],"latest_commit_sha":null,"homepage":"https://witchcrafters.github.io","language":"Elixir","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/witchcrafters.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":".github/CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2015-10-06T20:56:18.000Z","updated_at":"2025-09-22T21:08:53.000Z","dependencies_parsed_at":"2023-09-24T16:59:00.147Z","dependency_job_id":null,"html_url":"https://github.com/witchcrafters/witchcraft","commit_stats":{"total_commits":174,"total_committers":19,"mean_commits":9.157894736842104,"dds":0.367816091954023,"last_synced_commit":"6c61c3ecd5b431c52e8b60aafb05596d9182205e"},"previous_names":["expede/witchcraft"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/witchcrafters/witchcraft","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/witchcrafters%2Fwitchcraft","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/witchcrafters%2Fwitchcraft/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/witchcrafters%2Fwitchcraft/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/witchcrafters%2Fwitchcraft/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/witchcrafters","download_url":"https://codeload.github.com/witchcrafters/witchcraft/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/witchcrafters%2Fwitchcraft/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278425499,"owners_count":25984686,"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","status":"online","status_checked_at":"2025-10-05T02:00:06.059Z","response_time":54,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["algebra","algebraic-data-types","applicative","category","elixir","functor","monad","operators","traversable","type-class"],"created_at":"2024-09-24T20:29:20.022Z","updated_at":"2025-10-05T07:47:28.291Z","avatar_url":"https://github.com/witchcrafters.png","language":"Elixir","funding_links":["https://opencollective.com/witchcraft/contribute/tier/8074-backer","https://opencollective.com/witchcraft/contribute/tier/8075-sponsor"],"categories":[],"sub_categories":[],"readme":"![](https://github.com/expede/witchcraft/raw/main/brand/Wordmark/PNG/WC-wordmark-lrg@2x.png)\n\n`Witchcraft` is a library providing common algebraic and categorical abstractions to Elixir.\nMonoids, functors, monads, arrows, categories, and other dark magic right at your fingertips.\n\n[![Build Status](https://travis-ci.org/expede/witchcraft.svg?branch=master)](https://travis-ci.org/expede/witchcraft)\n[![Inline docs](http://inch-ci.org/github/expede/witchcraft.svg?branch=master)](http://inch-ci.org/github/expede/witchcraft)\n[![API Docs](https://img.shields.io/badge/api-docs-MediumPurple.svg?style=flat)](http://hexdocs.pm/witchcraft/)\n[![license](https://img.shields.io/github/license/mashape/apistatus.svg?maxAge=2592000)](https://github.com/expede/witchcraft/blob/master/LICENSE)\n\n[![](https://opencollective.com/witchcraft/tiers/backer.svg?avatarHeight=50)](https://opencollective.com/witchcraft/contribute/tier/8074-backer)\n\n[![](https://opencollective.com/witchcraft/tiers/sponsor.svg?avatarHeight=50)](https://opencollective.com/witchcraft/contribute/tier/8075-sponsor)\n\n# README\n\n## Table of Contents\n\n* [Quick Start](#quick-start)\n* [Library Family](#library-family)\n* [Values](#values)\n* [Type Class Hierarchy](#type-class-hierarchy)\n* [Writing Class Instances](#writing-class-instances)\n* [Operators](#operators)\n* [Haskell Translation Table](#haskell-translation-table)\n* [Prior Art and Further Reading](#prior-art-and-further-reading)\n* [Credits](#credits)\n\n## Quick Start\n\n```elixir\ndef deps do\n  [{:witchcraft, \"~\u003e 1.0\"}]\nend\n\n# ...\n\nuse Witchcraft\n```\n\n## Library Family\n\n```\nQuark    TypeClass\n    ↘    ↙\n   Witchcraft\n       ↓\n     Algae\n```\n\n| Name                                              | Description                                                   |\n|--------------------------------------------------:|---------------------------------------------------------------|\n| [`Quark`](https://hex.pm/packages/quark)          | Standard combinators (`id`, `compose`, \u0026c)                    |\n| [`TypeClass`](https://hex.pm/packages/type_class) | Used internally to generate type classes                      |\n| [`Algae`](https://hex.pm/packages/algae)          | Algebraic data types that implement `Witchcraft` type classes |\n\n## Values\n\n### Beginner Friendliness\n\nYou shouldn't have to learn another language just to understand powerful abstractions!\nBy enabling people to use a language that they already know, and is already in the\nsame ballpark in terms of values (emphasis on immutability, \u0026c), we can teach and\nlearn faster.\n\nAs much as possible, keep things friendly and well explained.\nConcrete examples are available via doctests.\n\n### Consistency \u0026 Ethos\n\nElixir does a lot of things differently from certain other functional languages.\nThe idea of a data \"subject\" being piped though functions is conceptually different from\npure composition of functions that are later applied. `Witchcraft` honours the\nElixir/Elm/OCaml way, and operators point in the direction that data travels.\n\nSome functions in the Elixir standard library have been expanded to work with more\ntypes while keeping the basic idea the same. For example, `\u003c\u003e` has been expanded\nto work on any [monoid](https://hexdocs.pm/witchcraft/Witchcraft.Monoid.html)\n(such as integers, lists, bitstrings, and so on).\n\nAll operators have named equivalents, and auto-currying variants of higher order functions\nare left at separate names so you can performance tune as needed (currying is helpful for\nmore abstract code). With a few exceptions (we're looking at you, `Applicative`),\npipe-ordering is maintained.\n\n### Pragmatism\nConvincing a company to use a language like [Haskell](https://www.haskell.org)\nor [PureScript](http://www.purescript.org) can be challenging. Elixir is gaining\na huge amount of interest. Many people have been able to introduce these concepts\ninto companies using Scala, so we should be able to do the same here.\n\nAll functions are compatible with regular Elixir code, and no types are enforced aside\nfrom what is used in protocol dispatch. Any struct can be made into a Witchcraft\nclass instance (given that it conforms to the properties).\n\n## Type Class Hierarchy\n\n```\nSemigroupoid  Semigroup  Setoid   Foldable   Functor -----------┐\n     ↓           ↓         ↓         ↓      ↙   ↓   ↘           |\n  Category     Monoid     Ord    Traversable  Apply  Bifunctor  |\n     ↓                                       ↙    ↘             ↓\n   Arrow                            Applicative   Chain       Extend\n                                             ↘    ↙             ↓\n                                              Monad           Comonad\n```\n\nHaving a clean slate, we have been able to use a clean set of type classes. This is largely\ntaken from the [Fantasy Land Specification](https://github.com/fantasyland/fantasy-land)\nand Edward Kmett's [`semigroupoids`](https://hackage.haskell.org/package/semigroupoids) package.\n\nAs usual, all `Applicative`s are `Functor`s, and all `Monad`s are `Applicative`s.\nThis grants us the ability to reuse functions in their child classes.\nFor example, `of` can be used for both `pure` and `return`, `lift/*` can handle\nboth `liftA*` and `liftM*`, and so on.\n\n### Import Chains\n\nIt is very common to want to import a class and all of its dependencies.\nYou can do this with `use`. For example, you can import the entire library with:\n\n```elixir\nuse Witchcraft\n```\n\nOr import a module plus all others that it depends on:\n\n```elixir\nuse Witchcraft.Applicative\n```\n\nAny options that you pass to `use` will be propagated all the way down the chain:\n\n```elixir\nuse Witchcraft.Applicative, except: [~\u003e: 2]\n```\n\nSome modules override `Kernel` operators and functions. While this is generally safe,\nif you would like to skip all overrides, pass `override_kernel: false` as an option:\n\n```elixir\nuse Witchcraft.Applicative, override_kernel: false\n\n# Or even\n\nuse Witchcraft, override_kernel: false\n```\n\n## Writing Class Instances\n\nHow to make your custom struct compatible with `Witchcraft`:\n\n1. Read the [`TypeClass` README](https://hexdocs.pm/type_class/readme.html)\n2. Implement the [`TypeClass` data generator protocol](https://hexdocs.pm/type_class/TypeClass.Property.Generator.html#content) for your struct\n3. Use [`definst`](https://hexdocs.pm/type_class/TypeClass.html#definst/3) (\"define instance\") instead of `defimpl`:\n\n```elixir\ndefinst Witchcraft.Functor, for: Algae.Id do\n  def map(%{id: data}, fun), do: %Algae.Id{id: fun.(data)}\nend\n```\n\nAll classes have properties that your instance must conform to at compile time.\n`mix` will alert you to any failing properties by name, and will refuse to compile\nwithout them. Sometimes it is not possible to write an instance that will pass the check,\nand you can either write a [custom generator](https://hexdocs.pm/type_class/readme.html#custom_generator-1)\nfor that instance, or [force](https://hexdocs.pm/type_class/readme.html#force_type_instance-true)\nthe instance. If you must resort to forcing the instance, please write a test\nof the property for some specific case to be reasonably sure that it will be compatible\nwith the rest of the library.\n\nMore reference instances are available in [`Algae`](https://github.com/expede/algae).\n\n## Operators\n\n| Family       | Function         | Operator |\n|-------------:|:-----------------|:---------|\n| Setoid       | `equivalent?`    | `==`     |\n|              | `nonequivalent?` | `!=`     |\n| Ord          | `greater_than?`  | `\u003e`      |\n|              | `lesser_than?`   | `\u003c`      |\n| Semigroup    | `append`         | `\u003c\u003e`     |\n| Functor      | `lift`           | `~\u003e`     |\n|              | `convey`         | `~\u003e\u003e`    |\n|              | `chain`          | `\u003e\u003e\u003e`    |\n|              | `over`           | `\u003c~`     |\n|              | `ap`             | `\u003c\u003c~`    |\n|              | `reverse_chain`  | `\u003c\u003c\u003c`    |\n| Semigroupoid | `compose`        | `\u003c\\|\u003e`   |\n|              | `pipe_compose`   | `\u003c~\u003e`    |\n| Arrow        | `product`        | `^^^`    |\n|              | `fanout`         | `\u0026\u0026\u0026`    |\n\n\n## Haskell Translation Table\n\n| Haskell Prelude | Witchcraft         |\n|----------------:|:-------------------|\n| `flip ($)`      | `\\|\u003e/2` (`Kernel`) |\n| `.`             | `\u003c\\|\u003e/2`           |\n| `\u003c\u003c\u003c`           | `\u003c\\|\u003e/2`           |\n| `\u003e\u003e\u003e`           | `\u003c~\u003e/2`            |\n| `\u003c\u003e`            | `\u003c\u003e/2`             |\n| `\u003c$\u003e`           | `\u003c~/2`             |\n| `flip (\u003c$\u003e)`    | `~\u003e/2`             |\n| `fmap`          | `lift/2`           |\n| `liftA`         | `lift/2`           |\n| `liftA2`        | `lift/3`           |\n| `liftA3`        | `lift/4`           |\n| `liftM`         | `lift/2`           |\n| `liftM2`        | `lift/3`           |\n| `liftM3`        | `lift/4`           |\n| `ap`            | `ap/2`             |\n| `\u003c*\u003e`           | `\u003c\u003c~/2`            |\n| `\u003c**\u003e`          | `~\u003e\u003e/2`            |\n| `*\u003e`            | `then/2`           |\n| `\u003c*`            | `following/2`      |\n| `pure`          | `of/2`             |\n| `return`        | `of/2`             |\n| `\u003e\u003e`            | `then/2`           |\n| `\u003e\u003e=`           | `\u003e\u003e\u003e/2`            |\n| `=\u003c\u003c`           | `\u003c\u003c\u003c/2`            |\n| `***`           | `^^^/2`            |\n| `\u0026\u0026\u0026`           | `\u0026\u0026\u0026/2`            |\n\n## Prior Art and Further Reading\n\nThis library draws heavy inspiration from mathematics, other languages,\nand other Elixir libraries. We would be ashamed not to mention them here.\nThere is much, much more out there, but these are our highlights and inspirations.\n\nThe [`Monad`](https://hexdocs.pm/monad/Monad.html) library predates `Witchcraft`\nby several years. This library proved that it is entirely possible\nto bring do-notation to Elixir. It takes a very different approach:\nit is very up-front that it has a very loose definition of what it means for\nsomething to be a \"monad\", and relies on `behaviour`s rather than ad-hoc polymorphism.\n\n[The Fantasy Land Spec](https://github.com/fantasyland/fantasy-land) is a spec for\nprojects such as this one, but targeted at Javascript. It does not come with its\nown implementation, but provides a [helpful chart](https://github.com/fantasyland/fantasy-land/raw/master/figures/dependencies.png)\nof class hierarchies.\n\nIn many ways, [`Scalaz`](https://github.com/scalaz/scalaz), and later [`cats`](http://typelevel.org/cats/),\nwere the first widely-used port of categorical \u0026 algebraic ideas to\na mainstream language. While dismissed by some as \"[Haskell fan fiction](https://twitter.com/plt_hulk/status/341292374355501056)\",\nit showed that we can write our own Haskell fanfic in all sorts of languages.\n\nObviously the Haskell [`Prelude`](https://hackage.haskell.org/package/base-4.10.0.0/docs/Prelude.html)\ndeserves mention. Haskell has inspired so many programmers to write clean,\ndeclarative, functional code based on principled abstractions. We'll spare you\nthe love letter to [SPJ](https://en.wikipedia.org/wiki/Simon_Peyton_Jones),\nthe Glasgow team, and the original Haskell committee, but we're deeply appreciative\nof how they pushed the state of the art forward.\n\n[`classy-prelude`/`mono-traversable`](https://github.com/snoyberg/mono-traversable)\nhave also made a lot of progress towards a base library that incorporates modern ideas\nin a clean package, and was an inspiration to taking a similar approach with Witchcraft.\n\nThe [`semigroupoids`](https://hackage.haskell.org/package/semigroupoids) library\nfrom the eminent [Edward Kmett](https://github.com/ekmett) provided many\nreference implementations and is helping set the future expansion of\nthe foldable class lineage in Witchcraft.\n\nInterested in learning more of the underlying ideas? The maintainers can heavily\nrecommend [Conceptual Mathematics](http://www.cambridge.org/catalogue/catalogue.asp?isbn=9780521719162),\n[Category Theory for the Sciences](https://mitpress.mit.edu/books/category-theory-sciences),\nand [Categories for the Working Mathematician](https://en.wikipedia.org/wiki/Categories_for_the_Working_Mathematician).\nReading these books probably won't change your code overnight. Some people call it\n\"[general abstract nonsense](https://en.wikipedia.org/wiki/Abstract_nonsense)\"\nfor a reason. That said, it does provide a nice framework for thinking about\nthese abstract ideas, and is a recommended pursuit for all that are curious.\n\n## Credits\n\n### Logo\nA big thank you to [Brandon Labbé](https://dribbble.com/brandonlabbe) for creating\nthe project logo.\n\n### Sponsor\n[Robot Overlord](http://robotoverlord.io) sponsors much of the development of Witchcraft,\nand dogfoods the library in real-world applications.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwitchcrafters%2Fwitchcraft","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwitchcrafters%2Fwitchcraft","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwitchcrafters%2Fwitchcraft/lists"}