Current section
Files
Jump to
Current section
Files
lib/ord.ex
defprotocol Funx.Ord do
@moduledoc """
The `Funx.Ord` protocol defines a set of comparison functions: `lt?/2`, `le?/2`, `gt?/2`, and `ge?/2`.
This protocol is intended for types that can be ordered, allowing values to be compared for their relative positions in a total order.
By implementing this protocol, you can provide custom logic for how values of a certain type are compared.
## Fallback
The protocol uses `@fallback_to_any true`, which means if a specific type does not implement `Funx.Ord`,
the default implementation for `Any` will be used, which relies on Elixir's built-in comparison operators.
"""
@fallback_to_any true
@doc """
Returns `true` if `a` is less than `b`, otherwise returns `false`.
## Examples
iex> Funx.Ord.lt?(Funx.Monad.Maybe.just(3), Funx.Monad.Maybe.just(5))
true
iex> Funx.Ord.lt?(Funx.Monad.Maybe.just(5), Funx.Monad.Maybe.just(3))
false
iex> Funx.Ord.lt?(Funx.Monad.Maybe.nothing(), Funx.Monad.Maybe.just(3))
true
"""
def lt?(a, b)
@doc """
Returns `true` if `a` is less than or equal to `b`, otherwise returns `false`.
## Examples
iex> Funx.Ord.le?(Funx.Monad.Maybe.just(3), Funx.Monad.Maybe.just(5))
true
iex> Funx.Ord.le?(Funx.Monad.Maybe.just(5), Funx.Monad.Maybe.just(5))
true
iex> Funx.Ord.le?(Funx.Monad.Maybe.just(5), Funx.Monad.Maybe.just(3))
false
"""
def le?(a, b)
@doc """
Returns `true` if `a` is greater than `b`, otherwise returns `false`.
## Examples
iex> Funx.Ord.gt?(Funx.Monad.Maybe.just(5), Funx.Monad.Maybe.just(3))
true
iex> Funx.Ord.gt?(Funx.Monad.Maybe.just(3), Funx.Monad.Maybe.just(5))
false
iex> Funx.Ord.gt?(Funx.Monad.Maybe.just(3), Funx.Monad.Maybe.nothing())
true
"""
def gt?(a, b)
@doc """
Returns `true` if `a` is greater than or equal to `b`, otherwise returns `false`.
## Examples
iex> Funx.Ord.ge?(Funx.Monad.Maybe.just(5), Funx.Monad.Maybe.just(3))
true
iex> Funx.Ord.ge?(Funx.Monad.Maybe.just(5), Funx.Monad.Maybe.just(5))
true
iex> Funx.Ord.ge?(Funx.Monad.Maybe.just(3), Funx.Monad.Maybe.just(5))
false
"""
def ge?(a, b)
end
defimpl Funx.Ord, for: Any do
@spec lt?(any(), any()) :: boolean()
def lt?(a, b), do: a < b
@spec le?(any(), any()) :: boolean()
def le?(a, b), do: a <= b
@spec gt?(any(), any()) :: boolean()
def gt?(a, b), do: a > b
@spec ge?(any(), any()) :: boolean()
def ge?(a, b), do: a >= b
end
defimpl Funx.Ord, for: DateTime do
@spec lt?(DateTime.t(), DateTime.t()) :: boolean()
def lt?(%DateTime{} = a, %DateTime{} = b), do: DateTime.compare(a, b) == :lt
@spec le?(DateTime.t(), DateTime.t()) :: boolean()
def le?(%DateTime{} = a, %DateTime{} = b),
do: match?(x when x in [:lt, :eq], DateTime.compare(a, b))
@spec gt?(DateTime.t(), DateTime.t()) :: boolean()
def gt?(%DateTime{} = a, %DateTime{} = b), do: DateTime.compare(a, b) == :gt
@spec ge?(DateTime.t(), DateTime.t()) :: boolean()
def ge?(%DateTime{} = a, %DateTime{} = b),
do: match?(x when x in [:gt, :eq], DateTime.compare(a, b))
end
defimpl Funx.Ord, for: Date do
@spec lt?(Date.t(), Date.t()) :: boolean()
def lt?(a, b), do: Date.compare(a, b) == :lt
@spec le?(Date.t(), Date.t()) :: boolean()
def le?(a, b), do: match?(x when x in [:lt, :eq], Date.compare(a, b))
@spec gt?(Date.t(), Date.t()) :: boolean()
def gt?(a, b), do: Date.compare(a, b) == :gt
@spec ge?(Date.t(), Date.t()) :: boolean()
def ge?(a, b), do: match?(x when x in [:gt, :eq], Date.compare(a, b))
end
defimpl Funx.Ord, for: Time do
@spec lt?(Time.t(), Time.t()) :: boolean()
def lt?(%Time{} = a, %Time{} = b), do: Time.compare(a, b) == :lt
@spec le?(Time.t(), Time.t()) :: boolean()
def le?(%Time{} = a, %Time{} = b),
do: match?(x when x in [:lt, :eq], Time.compare(a, b))
@spec gt?(Time.t(), Time.t()) :: boolean()
def gt?(%Time{} = a, %Time{} = b), do: Time.compare(a, b) == :gt
@spec ge?(Time.t(), Time.t()) :: boolean()
def ge?(%Time{} = a, %Time{} = b),
do: match?(x when x in [:gt, :eq], Time.compare(a, b))
end
defimpl Funx.Ord, for: NaiveDateTime do
@spec lt?(NaiveDateTime.t(), NaiveDateTime.t()) :: boolean()
def lt?(%NaiveDateTime{} = a, %NaiveDateTime{} = b), do: NaiveDateTime.compare(a, b) == :lt
@spec le?(NaiveDateTime.t(), NaiveDateTime.t()) :: boolean()
def le?(%NaiveDateTime{} = a, %NaiveDateTime{} = b),
do: match?(x when x in [:lt, :eq], NaiveDateTime.compare(a, b))
@spec gt?(NaiveDateTime.t(), NaiveDateTime.t()) :: boolean()
def gt?(%NaiveDateTime{} = a, %NaiveDateTime{} = b), do: NaiveDateTime.compare(a, b) == :gt
@spec ge?(NaiveDateTime.t(), NaiveDateTime.t()) :: boolean()
def ge?(%NaiveDateTime{} = a, %NaiveDateTime{} = b),
do: match?(x when x in [:gt, :eq], NaiveDateTime.compare(a, b))
end