View Source Funx.Appendable protocol (funx v0.1.0)
A protocol for combining values in a generic, extensible way.
The Appendable
protocol defines how two values of the same type can be combined. It is
used throughout Funx in functions like traverse_a/2
and wither_a/2
to accumulate
intermediate results without coupling logic to a specific type.
This protocol enables functions to remain flexible and composable when reducing, aggregating, or accumulating values across a wide variety of domains.
Required functions
coerce/1
– Normalizes an input value into a form suitable for aggregation.append/2
– Combines two values of the same type into one.
Default – Flat list aggregation
A fallback implementation is provided for all types that do not define a specific
Appendable
instance. This default uses list concatenation as a universal aggregation
strategy: all inputs are coerced into lists (if not already), and combined using ++
.
When using the default aggregation strategy, values are collected in a plain list:
validate_positive = fn x ->
Funx.Monad.Either.lift_predicate(x, &(&1 > 0), fn v -> "Value must be positive: " <> to_string(v) end)
end
validate_even = fn x ->
Funx.Monad.Either.lift_predicate(x, &(rem(&1, 2) == 0), fn v -> "Value must be even: " <> to_string(v) end)
end
Funx.Monad.Either.validate(4, [validate_positive, validate_even])
#=> %Funx.Monad.Either.Right{right: 4}
Funx.Monad.Either.validate(3, [validate_positive, validate_even])
#=> %Funx.Monad.Either.Left{left: ["Value must be even: 3"]}
Funx.Monad.Either.validate(-3, [validate_positive, validate_even])
#=> %Funx.Monad.Either.Left{left: ["Value must be positive: -3", "Value must be even: -3"]}
Structured aggregation with ValidationError
You can also use a custom struct to hold errors. This example uses ValidationError
:
alias Funx.Errors.ValidationError
validate_positive = fn x ->
Funx.Monad.Either.lift_predicate(x, &(&1 > 0), fn v -> "Value must be positive: " <> to_string(v) end)
|> Funx.Monad.Either.map_left(&ValidationError.new/1)
end
validate_even = fn x ->
Funx.Monad.Either.lift_predicate(x, &(rem(&1, 2) == 0), fn v -> "Value must be even: " <> to_string(v) end)
|> Funx.Monad.Either.map_left(&ValidationError.new/1)
end
Funx.Monad.Either.validate(-3, [validate_positive, validate_even])
#=> %Funx.Monad.Either.Left{
# left: %ValidationError{
# errors: ["Value must be positive: -3", "Value must be even: -3"]
# }
# }
Summary
Functions
Combines two values into a single result.
Normalizes a single input value into a form suitable for accumulation.
Types
@type t() :: term()
All the types that implement this protocol.
Functions
Combines two values into a single result.
Implementations must ensure the operation is associative within their type. For types that require disambiguation or structural control, define a custom implementation.
Normalizes a single input value into a form suitable for accumulation.