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