Packages

A Practical Combinator Library

Current section

Files

Jump to
apcl lib apcl.ex
Raw

lib/apcl.ex

defmodule Apcl do
@moduledoc """
A Practical Combinator Library.
"""
@doc """
Defines a function with an implicit parameter `x`.
This macro allows you to define a function that takes a single parameter `x`
and applies the body expression (which should return a function) to it.
## Examples
defc composed_fun, do: compose(f, g)
# Expands to: def composed_fun(x), do: compose(f, g).(x)
The parameter `x` is automatically generated as a unique symbol to avoid capture.
"""
defmacro defc(name, do: body) do
x = {:x, [], Elixir}
call = {{:., [], [body]}, [], [x]}
# name is already AST like {:add_one, [...], nil}, extract the atom
name_atom = elem(name, 0)
signature = {name_atom, [], [x]}
{:def, [], [signature, [do: call]]}
end
@doc """
Returns its argument.
"""
def identity(x), do: x
@doc """
Returns a function which returns `x` no matter what it is passed.
"""
def constant(x), do: fn _y -> x end
@doc """
Performs function composition.
"""
def compose(f, g), do: fn x -> f.(g.(x)) end
@doc """
Returns a function which applies `f` to `xs`.
"""
def apply(f), do: fn xs -> apply(f, xs) end
@doc """
Returns a function which permutes its arguments and applies `f` to them.
"""
def flip(f), do: fn x, y -> f.(y, x) end
@doc """
Given two arguments, returns the left one.
"""
def left(x, _y), do: x
@doc """
Given two arguments, returns the right one.
"""
def right(_x, y), do: y
@doc """
Returns a function that applies `g` and `h` to its arguments, taking the
resulting values as the arguments to `f`.
"""
def recombine(f, g, h), do: fn x -> f.(g.(x), h.(x)) end
@doc """
Returns a function that applies `g` to each of its arguments, taking the
resulting values as the arguments to `f`.
"""
def under(f, g), do: fn x, y -> f.(g.(x), g.(y)) end
end