Current section

Files

Jump to
funx lib utils.ex
Raw

lib/utils.ex

defmodule Funx.Utils do
@moduledoc """
A collection of higher-order functions for functional programming in Elixir.
This module provides utilities for working with functions in a functional
programming style. It includes:
- `curry/1`: Transforms a multi-argument function into a curried version.
- `curry_r/1`: Transforms a multi-argument function into a curried version, but from right to left.
- `flip/1`: Reverses the argument order of a two-argument function.
"""
@doc """
Transforms a function of arity `n` into a curried version,
allowing it to be applied one argument at a time.
## Example
iex> add = fn a, b -> a + b end
iex> curried_add = FunPark.Utils.curry(add)
iex> add_three = curried_add.(3)
iex> add_three.(2)
5
"""
@spec curry((... -> any())) :: any()
def curry(fun) when is_function(fun) do
arity = :erlang.fun_info(fun, :arity) |> elem(1)
curry(fun, arity, [])
end
defp curry(fun, 1, args),
do: fn last_arg -> apply(fun, args ++ [last_arg]) end
defp curry(fun, arity, args) when arity > 1 do
fn next_arg -> curry(fun, arity - 1, args ++ [next_arg]) end
end
@doc """
Alias for `curry/1`, explicitly denoting left-to-right argument application.
## Example
iex> subtract = fn a, b -> a - b end
iex> curried_subtract = FunPark.Utils.curry_l(subtract)
iex> subtract_five = curried_subtract.(5)
iex> subtract_five.(3)
2
"""
@spec curry_l((... -> any())) :: any()
def curry_l(fun) when is_function(fun), do: curry(fun)
@doc """
Transforms a function of arity `n` into a right-curried version,
applying arguments from right to left.
## Example
iex> divide = fn a, b -> a / b end
iex> curried_divide = FunPark.Utils.curry_r(divide)
iex> divide_by_two = curried_divide.(2)
iex> divide_by_two.(10)
5.0
"""
@spec curry_r((... -> any())) :: any()
def curry_r(fun) when is_function(fun) do
arity = :erlang.fun_info(fun, :arity) |> elem(1)
curry_r(fun, arity, [])
end
defp curry_r(fun, 1, args),
do: fn last_arg -> apply(fun, [last_arg | args]) end
defp curry_r(fun, arity, args) when arity > 1 do
fn next_arg -> curry_r(fun, arity - 1, [next_arg | args]) end
end
@doc """
Reverses the argument order of a two-argument function.
The `flip/1` function takes a function of arity 2 and returns a new function
where the first and second arguments are swapped.
## Examples
iex> divide = fn a, b -> a / b end
iex> flipped_divide = Utils.flip(divide)
iex> flipped_divide.(2, 10)
5.0
"""
@spec flip((a, b -> c)) :: (b, a -> c) when a: any(), b: any(), c: any()
def flip(fun) when is_function(fun, 2) do
fn a, b -> fun.(b, a) end
end
@spec summarize_string(binary()) :: binary()
def summarize_string(value, max_len \\ 50) when is_binary(value) do
if String.length(value) > max_len do
String.slice(value, 0, max_len) <> "..."
else
value
end
end
end