recursion_schemes v0.1.0 RecursionSchemes
Generic recursion schemes for working with recursively defined data structures.
Recursion schemes provide functionality for consuming and creating recursive structures; they factor out the explicit recursion.
The requirement for using these functions with user defined recursive data structures is an implementation of the RecStruct protocol.
See Functional Programming with Bananas Lenses Envelopes and Barbed Wire for the seminal paper describing recursion schemes.
Link to this section Summary
Functions
ana/3
(anamorphism) generalizes unfolding a recursive structure
cata/3
(catamorphism) is a function for consuming a recursive data structure
hylo/2
generalizes unfolding a recursive structure and applying a catamorphism
to the result
hylo/5
(hylomorphism) generalizes unfolding a recursive structure and folding
the result
Link to this section Functions
ana((any -> boolean), (any -> {any, any})) :: ({any, any} -> any)
ana/2
returns a closure over ana/3
so that you can define arity-1 functions
in terms of ana.
Examples
iex> zip = RecursionSchemes.ana(
...> fn {as, bs} -> as == [] || bs == [] end,
...> fn {[a | as], [b | bs]} -> {{a, b}, {as, bs}} end)
...> zip.({{[1,2,3,4], ["a", "b", "c"]}, []})
[{1, "a"}, {2, "b"}, {3, "c"}]
ana({any, any}, (any -> boolean), (any -> {any, any})) :: any
ana/3
(anamorphism) generalizes unfolding a recursive structure.
Given a {seed value, accumulator} tuple, a predicate to end the unfolding, and a function that takes a seed value and returns a tuple of {value to accumulate, next seed}, returns an unfolded structure.
Not guaranteed to terminate; unfolding ends when the finished?
predicate returns true. If finished?
never evaluates to true,
the unfolding will never end.
ana :: {a, f a} -> (a -> bool) -> (a -> {a, a}) -> f a
Examples
iex> RecursionSchemes.ana(
...> {1, []}, # Initial state; starting value and accumulator
...> fn x -> x > 5 end, # End unfolding after five iterations
...> fn x -> {x * x, x + 1} end)
[1, 4, 9, 16, 25]
iex> RecursionSchemes.ana(
...> {1, 0},
...> fn x -> x == 16 end,
...> fn x -> {x, x + 1} end)
120
cata/2
returns a closure over cata/3
with the accumulator and function applied.
Examples
iex> my_sum = RecursionSchemes.cata(
...> 0,
...> fn (h, acc) -> h + acc end)
...> my_sum.([3, 5, 2, 9])
19
iex> factorial = RecursionSchemes.cata(
...> 1,
...> fn (n, acc) -> n * acc end)
...> factorial.(5)
120
cata/3
(catamorphism) is a function for consuming a recursive data structure.
It is a generalization of fold; when operating on lists, it is equivalent to List.foldr/3
Given three arguments, a data structure, an accumulator, and a function, it applies the function to the elements of the data structure and rolls them into the accumulator.
cata :: f a -> b -> (a -> b -> b) -> b
Examples
iex> [3, 5, 2, 9]
...> |> RecursionSchemes.cata(
...> 0,
...> fn (h, acc) -> h + acc end)
19
iex> 5
...> |> RecursionSchemes.cata(
...> 1,
...> fn (n, acc) -> n * acc end)
120
hylo/2
generalizes unfolding a recursive structure and applying a catamorphism
to the result.
It takes an already defined catamorphism and anamorphism as its arguments.
Not guaranteed to terminate; unfolding ends when the finished?
predicate returns true. If finished?
never evaluates to true,
the unfolding will never end.
Examples
iex> five_squares = RecursionSchemes.ana(
...> fn x -> x > 5 end, # End unfolding after five iterations
...> fn x -> {x * x, x + 1} end)
...> my_sum = RecursionSchemes.cata(
...> 0,
...> fn (h, acc) -> h + acc end)
...> RecursionSchemes.hylo(five_squares, my_sum).({1, []})
55
hylo({any, any}, (any -> boolean), (any -> {any, any}), any, (any, any -> any)) :: any
hylo/5
(hylomorphism) generalizes unfolding a recursive structure and folding
the result.
Not guaranteed to terminate; unfolding ends when the finished?
predicate returns true. If finished?
never evaluates to true,
the unfolding will never end.
Examples
iex> RecursionSchemes.hylo(
...> {1, []}, # Initial state; starting value and accumulator
...> fn x -> x > 5 end, # End unfolding after five iterations
...> fn x -> {x * x, x + 1} end,
...> 0,
...> fn (h, acc) -> h + acc end)
55