View Source Funx.List Usage Rules

Quick Reference

  • All functions operate on Elixir lists ([term()]).
  • Eq is used for: uniq/2, union/3, intersection/3, difference/3, symmetric_difference/3, subset?/3, and superset?/3.
  • Ord is used for: sort/2 and strict_sort/2.
  • strict_sort/2 combines Ord (for sorting) and Eq (for deduplication).
  • All functions default to protocol dispatch; no wiring needed if instances exist.
  • Ad-hoc comparators can be passed using Eq.Utils.contramap/1 or Ord.Utils.contramap/1.

Overview

The Funx.List module provides equality- and ordering-aware utilities for working with lists. It supports deduplication, sorting, and set-like behavior using Eq and Ord instances.

This allows logic like "unique cars by VIN" or "sort by price, then mileage" to be clean, composable, and domain-aware.

Eq-Based Operations

uniq/2

Removes duplicates using Eq.

Funx.List.uniq([%Car{vin: "A"}, %Car{vin: "A"}])
# => [%Car{vin: "A"}]

With custom comparator:

eq = Eq.Utils.contramap(& &1.make)
Funx.List.uniq(cars, eq)

union/3

Combines two lists, removing duplicates using Eq.

Funx.List.union([1, 2], [2, 3])
# => [1, 2, 3]

intersection/3

Returns the elements common to both lists.

Funx.List.intersection([1, 2, 3], [2, 3, 4])
# => [2, 3]

difference/3

Returns elements from the first list that are not in the second.

Funx.List.difference([1, 2, 3], [2])
# => [1, 3]

symmetric_difference/3

Returns elements that appear in only one of the two lists.

Funx.List.symmetric_difference([1, 2], [2, 3])
# => [1, 3]

subset?/3 and superset?/3

Checks for inclusion using Eq.

Funx.List.subset?([1, 2], [1, 2, 3])
# => true

Funx.List.superset?([1, 2, 3], [1, 2])
# => true

Ord-Based Operations

sort/2

Sorts the list using Ord. Defaults to protocol dispatch.

Funx.List.sort([3, 1, 2])
# => [1, 2, 3]

With ad-hoc ordering:

ord = Ord.Utils.contramap(& &1.price)
Funx.List.sort(cars, ord)

strict_sort/2

Sorts the list and removes duplicates. Uses Ord for sorting and derives Eq from ordering.

Funx.List.strict_sort([3, 1, 3, 2])
# => [1, 2, 3]

Concatenation

concat/1

Concatenates a list of lists left-to-right using the ListConcat monoid.

Funx.List.concat([[1], [2, 3], [4]])
# => [1, 2, 3, 4]

Good Patterns

  • Use uniq/2, intersection/3, and related functions instead of manual deduplication.
  • Use contramap/1 to lift equality or ordering by projecting key fields.
  • Use strict_sort/2 when you need sorted unique results.
  • Define protocol instances for domain types to remove the need for custom comparator logic.

Anti-Patterns

  • Using == in list operations instead of Eq:

    # BAD
    Enum.uniq_by(users, & &1.id)  # not composable or testable
  • Sorting maps or structs without defining Ord:

    # BAD
    Enum.sort([%User{}])  # may raise
  • Mixing raw and protocol-based comparison:

    # BAD
    if user1.id == user2.id and Eq.eq?(user1, user2), do: ...

When to Use

Use Funx.List when:

  • You want list operations that follow your domain's equality or ordering rules.
  • You need composable set logic like union or difference.
  • You want deterministic, extensible sorting.
  • You're working with domain types (e.g., User, Car, Ticket) and want safe behavior.