/elixir-fun_land

Algebraic Data Types for Elixir: Both functional and fun.

Primary LanguageElixirMIT LicenseMIT

FunLand

hex.pm version Build Status

FunLand adds Behaviours to define Algebraic Data Types ('Container' data types) to Elixir, including many helpful operations with them. Where applicable, an ADT implementation for Elixir's built-in types like Lists, Maps, Strings and Functions are included.

Also included are some implementations of commonly-used ADTs, for your leisure. (These might be split off in their own library in the future)

FunLand is based on ideas of the Fantasy Land JavaScript specification for Algebraic Data Types, as well as the implementations of ADTs in other languages, such as Haskell and Idris.

FunLand attempts to use understandable names for the different behaviours and functions, to make ADTs as approachable to newcomers as possible.

Pre-release version

As can be seen below in the roadmap, FunLand is not fully finished yet. New pre-release versions might introduce backwards-incompatible changes.

Mostly lacking are:

  • Enough documentation.
  • Tests for most of the example implementations in FunLand.Builtin.*.

Changelog

  • 0.10.0
    • Fixes badly named module Reducable -> Reducible. Thank you, Eksperimental!
    • Makes Reducible.to_list/1 overridable so you can add your own implementation for it if you desire.
  • 0.9.3 - Fixes bug that made it impossible to compile on Elixir 1.8.x
  • 0.9.2 - Numbers v5.0.0 support
  • 0.9.1 - Fixes dispatching of Builtin Structs to proper behaviour implementation modules. Adds Combinable and Reducable implementations for MapSet.
  • 0.9.0 - Split off FunLandic to its own library.
  • 0.8.0 - Important (backwards-incompatible) naming and functionality changes. Implementation of Traversable. Implementations for the SuccessTuple type.

Roadmap

  • The most commong Algebraic Data Types, built as Behaviours that can be added to your own modules/structs:
    • Mappable - any structure you can map over: changing the contents without changing the structure.
    • Appliable - any Mappable structure you can combine two of, where the first contains a function to apply_with the contents of the second, returning a new strucure.
    • Applicative - any Appliable structure that can be created from any value you want to wrap inside.
    • Chainable - any Appliable structure that you can bind functions to, which, when given the contents of the structure, return a new version of the structure.
    • Monad - Anything structure that is both Applicative and Chainable, which makes them super flexible!
      • Monadic do-notation. (The implementation is heavily based on code from the monad library. Lots of thanks!)
        • let statements inside the monadic do-notation.
    • Semicombinable - Anything which, when you have two of them, you can combine them together into one.
    • Combinable - Anything that is Combinable, and also has a neutral value which you can combine something with when you don't have anything else, to keep the result the same.
    • CombinableMonad - Any structure that is both a Monad and Combinable.
    • Reducible - Any structure that can be reduced to a single value, when given a Combinable (or alternatively, a starting value and a function to combine this with a single value inside the structure).
    • Traversable
      • Find out how to implement Traversable.traverse properly in a dynamically typed language. (How do you know what empty structure to return when being passed an empty structure?) -> Pass explicit extra parameter with result module.
  • Also, where to put these practical implementations? -> FunLandic.*
  • How to write proper code for the built-in types like List? (What to put in the monadic syntax? etc.)
  • Catcheable exceptions instead of raised strings.
  • Implement some practical Algebraic Data Types to show what can be done with them:
    • List - the list we all know and love.
    • Maybe - either just filled with something, or empty (nothing inside)
    • Reader - store a state in a reader monad and refer to it only when you need it later on.
    • Writer - Keep a log of the things that happened alongside your computations.
    • A Custom Behaviour you can expand upon yourself, with your own log-appending mechanism.
    • IOListWriter, which logs using an IOList (an implementation of the writer behaviour that is useful in most common circumstances).
    • Sum - Combine any Mappable filled with numbers by summing them.
    • Product - Combine any Mappable filled with numbers by multiplying them.
    • Any - Combine any Mappable filled with booleans by checking if some property is true for at least one of them.
    • All - Combine any Mappable filled with booleans by checking if some property is true for all of them.
    • Either/Result - Contains two results, returns the first result of the two that is not empty.
    • SuccessTuple implementation of Either/Maybe! Wow!
    • Fully write this readme.
  • Extend documentation.
    • More Fruit Salad explanations.
  • Write as many tests as possible.
  • Revisit+extend code examples.

Later Future:

  • Comonad
  • Improve documentation, better fruit salad descriptions?

Installation

The package is available on hex and can can be specified as a dependency by adding the snippet below in your mix.exs.

def deps do
  [{:fun_land, "~> 0.9.2"}]
end