Current section

Files

Jump to
funx lib monoid optics traversal_combine.ex
Raw

lib/monoid/optics/traversal_combine.ex

defmodule Funx.Monoid.Optics.TraversalCombine do
@moduledoc """
The `Funx.Monoid.Optics.TraversalCombine` module provides a monoid wrapper for parallel traversal combination.
This wrapper allows traversals to be used with generic monoid operations like `m_concat/2`,
enabling functional aggregation of multiple optics into a single multi-focus traversal.
### Wrapping and Unwrapping
- `new/1`: Wraps a traversal in a `TraversalCombine` monoid.
- `unwrap/1`: Extracts the traversal from a `TraversalCombine` wrapper.
### Monoid Operations (via protocol)
- `empty/1`: Returns the identity traversal (no foci).
- `append/2`: Combines two traversals by concatenating their foci.
- `wrap/2`: Wraps an optic into a single-focus traversal.
## Examples
iex> alias Funx.Monoid.Optics.TraversalCombine
iex> alias Funx.Optics.{Lens, Traversal}
iex> optics = [Lens.key(:name), Lens.key(:age)]
iex> t = Funx.Monoid.Utils.m_concat(%TraversalCombine{}, optics)
iex> Traversal.to_list(%{name: "Alice", age: 30}, t)
["Alice", 30]
"""
alias Funx.Optics.Traversal
@type t :: %__MODULE__{
traversal: Traversal.t()
}
defstruct traversal: nil
@doc """
Wraps a traversal in a TraversalCombine monoid.
"""
@spec new(Traversal.t()) :: t()
def new(%Traversal{} = traversal), do: %__MODULE__{traversal: traversal}
@doc """
Extracts the traversal from a TraversalCombine wrapper.
"""
@spec unwrap(t()) :: Traversal.t()
def unwrap(%__MODULE__{traversal: traversal}), do: traversal
end
defimpl Funx.Monoid, for: Funx.Monoid.Optics.TraversalCombine do
alias Funx.Monoid.Optics.TraversalCombine
alias Funx.Optics.{Lens, Prism, Traversal}
@doc """
Returns the identity traversal (no foci).
This is the identity element for combine: a traversal that contributes no foci.
"""
def empty(_) do
TraversalCombine.new(Traversal.identity())
end
@doc """
Combines two traversals by concatenating their foci lists.
This is parallel composition: the resulting traversal targets all foci from both inputs.
"""
def append(%TraversalCombine{traversal: t1}, %TraversalCombine{traversal: t2}) do
combined = %Traversal{foci: t1.foci ++ t2.foci}
TraversalCombine.new(combined)
end
@doc """
Wraps an optic (Lens or Prism) into a single-focus traversal.
"""
def wrap(_monoid, %Lens{} = lens) do
TraversalCombine.new(%Traversal{foci: [lens]})
end
def wrap(_monoid, %Prism{} = prism) do
TraversalCombine.new(%Traversal{foci: [prism]})
end
@doc """
Extracts the traversal from the TraversalCombine wrapper.
"""
def unwrap(%TraversalCombine{traversal: traversal}), do: traversal
end