# Haex

_"Haskell as Elixir"_ - A DSL for implementing Haskell style sum and product data types in Elixir

_(pronounced "hacks")_

A succinct statement generates a number of modules, and helper functions,
along with valid dialyzer type and specs to work with those data structures.

The goal is to make it quicker and easier to work with rich types without
having to implement a lot of boilerplate code to build common patterns. This
is particularly true in the case of Elixir structs, which to be used
properly, require a `defstruct` call, `@type` declaration (which is _almost
but not quite_ identical), and an `@enforce_keys` annotaiton. All of these
can be automated away.

A secondary goal is to encourage good use of types that are understand by
dialzyer. This makes it easier to work with and reason about the code, and
aids documentation of what functions expect and return.
### Basics
import Haex

data Maybe.t(a) :: Nothing | Just.t(a)

# {Maybe.Just, "cheese"}"cheese")
# {Maybe.Just, "cheese"}

# Maybe.Nothing
# Maybe.Nothing

When compiled from file, and loaded in iex...

iex(1)> t Maybe
@type t(a) :: Maybe.Nothing.t() | Maybe.Just.t(a)

iex(2) h Maybe.just
def just(arg1)
@spec just(a) :: t(a) when a: var

iex(3) h Maybe.nothing
def nothing()
@spec nothing() :: t(_a)

This one line statement (`Maybe.t(a) :: Nothing | Just.t(a)`) generated code that looks something like...
defmodule Maybe do
  @type t(a) :: Maybe.Nothing.t() | Maybe.Just.t(a)

  defmodule Nothing  do
    @opaque t() :: __MODULE__

    @spec(new() :: t())
    def new()  do

  defmodule Just do
    @opaque t(a) :: {__MODULE__, a}

    @spec(new(a) :: t(a) when a: var)
    def new(arg1) do
      {__MODULE__, arg1}

  @spec nothing() :: t(_a) when _a: var
  def nothing() do

  @spec just(a) :: t(a) when a: var)
  def just(arg1) do

...saving you a lot of keyboard wear

### Enum Types
data Color :: Red | Green | Blue | BlueSteel

### Sum Types
data SocialMediaAccount ::
        | Facepalm.t(String.t())
        | Watzap.t(String.t())
        | Instaban.t(String.t())

### Product Types
data Pair.t(a, b) :: Pair.t(a, b)

data Either.t(a, b) :: Left.t(a) | Right.t(b)

data Person::
          name: String.t(),
          social_media: [SocialMediaAccount.t()],
          age: integer(),
          height: float(),
          favourite_ice_cream: String.t(),
          standard_quote: String.t()
## Installation

If [available in Hex](, the package can be installed
by adding `haex` to your list of dependencies in `mix.exs`:

def deps do
    {:haex, "~> 0.1.0"}

Documentation can be generated with [ExDoc](
and published on [HexDocs]( Once published, the docs can
be found at [](