Skip to content

Repository files navigation

cmp_gleam

Package VersionHex DocsCI

A tiny, focused library for building small, composable comparators in Gleam. It intentionally avoids magic (no derives, no hidden behavior) so that comparison logic remains explicit, easy to test and easy to reason about.

Features

  • ✨ Small and predictable API
  • 🔧 Composable building blocks for lexicographic and tie-breaker ordering
  • 🎯 Support for custom normalization/folding functions
  • 🔒 Type-safe and total functions (no panics, no unsafe code)

Why this approach?

The library favors explicitness over implicit derivation. By making comparators first-class and composable you get predictable behaviour, easier testing, and straightforward integration with normalization libraries when you need to handle real-world Unicode data.

Installation

gleam add cmp_gleam

Then import the cmp module in your code:

importcmp

Quick examples

1. Sort integers

importcmpimportgleam/listpubfnsort_ints(xs:List(Int))->List(Int){list.sort(xs,by:cmp.natural_int)}

2. Sort records by a field (contramap pattern)

importcmpimportgleam/listimportgleam/stringtypeUser{User(name:String,age:Int)}pubfnsort_by_name(users:List(User))->List(User){letcmp_name=cmp.by(fn(u){caseu{User(name,_)->name}},string.compare)list.sort(users,by:cmp_name)}

3. Lexicographic ordering (chain / then / lazy_then)

Combine multiple comparators to sort by primary key, then by secondary key:

letcomparator=cmp.chain([cmp.by(fn(u){caseu{User(name,_)->name}},string.compare),cmp.by(fn(u){caseu{User(_,age)->age}},cmp.natural_int)])list.sort(users,by:comparator)

Unicode & normalization notes

  • string.compare compares strings as-is; composed vs decomposed characters may behave differently if not normalized.
  • For user-facing sorting (names, titles), you may want to normalize (NFC/NFD) or apply folding (remove accents) before comparing.
  • Use by_normalized_string or by_string_with to apply custom normalization functions.
  • This library has been tested with str for Unicode normalization and ASCII folding (e.g., str.extra.ascii_fold).

Performance tip: precompute normalized keys

When sorting large lists by normalized strings, calling normalize on every comparison is expensive. Use the decorate-sort-undecorate pattern:

importgleam/list// 1. Decorate: precompute normalized keys onceletdecorated=list.map(users,fn(u){letnormalized_name=your_normalize_fn(u.name)#(u,normalized_name)})// 2. Sort by the precomputed keyletsorted_decorated=list.sort(decorated,by:cmp.by(fn(pair){pair.1},string.compare))// 3. Undecorate: extract the original valuesletsorted_users=list.map(sorted_decorated,fn(pair){pair.0})

API overview

The library exports a single module cmp with the following main functions:

  • Basic comparators: natural_int, natural_string, natural_float
  • Contramap helpers: by, by_int, by_string, by_float, by_string_with, by_normalized_string
  • Composition: then, chain, lazy_then, reverse
  • Containers: option, list_compare, pair, triple

See the full API documentation for details.

Development

gleam test# Run the tests
gleam build # Build the project

License

MIT License - see LICENSE file for details.

About

Explicit equality & ordering lib for Gleam

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages