ExUnion is meant to be a lightweight, elixir-y implementation of tagged unions (also called variant, discriminated union, sum type, etc.).
While conventionally Elixir tends to promote using tuples to model tagged unions - the {:ok, ...} | {:error, ...} pattern being a good example of that - this approach arguably lacks expressiveness, especially when modeling non-trivial unions. An alternative is to employ structs to model the individual cases of a tagged union, which works nicely but has the disadvantage of requiring significant boilerplate code.
ExUnion attempts to bridge this gap by generating the necessary boilerplate (and a bit more) through a concise albeit opinionated DSL. Below the following links you can see an example for an idea on how you might use ExUnion.
defmodule Maybe do
import ExUnion
defunion some(value) | none
end
iex> Maybe.none()
%Maybe.None{}
iex> Maybe.some("string!")
%Maybe.Some{value: "string!"}
# Requiring is necessary since `is_maybe` is a guard (defguard)
iex> require Maybe
iex> Maybe.is_maybe("What's the meaning of life, the universe, and everything?")
false
iex> Maybe.is_maybe(42)
false
iex> Maybe.is_maybe(Maybe.none())
true
For more examples take a look at the project’s README.
Is the following usage considered asserting on information that’s an implementation detail? Or this is exactly how your library should be used when it comes to pattern matching?
The docs are good, I am simply making sure because e.g. Ecto still has some structs whose fields are well-known but it’s still not recommended to rely on them always being there. Hence my question.
Thanks for the splendid library! Now the choice types can be expressed even shorter than in F# (comparing to the examples from Domain Modeling Made Functional book by Scott Wlaschin).