README

#cmp

This package provides utility functions for comparing values and the Reverse newtype wrapper for reversing comparison order.

#Generic Comparison Functions

The library provides generic comparison functions that work with any type implementing the Compare trait:

///|
test "generic comparison" {
// Works with numbers
inspect(@cmp.maximum(3, 4), content="4")
inspect(@cmp.minimum(3, 4), content="3")
debug_inspect(@cmp.minmax(3, 4), content="(3, 4)")
}

#Reverse Comparison Order

The @cmp.Reverse[T] newtype wrapper reverses the comparison order of any type implementing Compare. This is particularly useful for:

  • Creating min-heaps from max-heap data structures
  • Sorting in descending order
  • Reversing the priority in priority queues

///|
test "reverse comparison" {
let a = @cmp.Reverse(1)
let b = @cmp.Reverse(2)

// Normal comparison: 1 < 2, but reversed: 1 > 2
inspect(a.compare(b), content="1")
inspect(b.compare(a), content="-1")

// Can be used with generic comparison functions
@debug.debug_inspect(@cmp.maximum(a, b), content="Reverse(1)")
@debug.debug_inspect(@cmp.minimum(a, b), content="Reverse(2)")
}

#Using Reverse with Collections

@cmp.Reverse can be used with sorted collections to change their ordering:

///|
test "reverse with arrays" {
// Create an array with reversed integers for descending sort
let arr : ReadOnlyArray[@cmp.Reverse[Int]] = [
Reverse(3),
Reverse(1),
Reverse(4),
Reverse(2),
]
// When sorted, the array will be in descending order of the wrapped values
@debug.debug_inspect(arr[0], content="Reverse(3)") // Access first element
}

#Comparison by Key

With @cmp.maximum_by_key() and @cmp.minimum_by_key(), it is possible to compare values based on arbitrary keys derived from the them. This is particularly useful when you need to compare complex objects based on some specific aspect or field.

///|
priv struct Person {
name : String
age : Int
} derive(Debug)

///|
test "cmp_by_key" {
// Compare strings by their length
let s1 = "hello"
let s2 = "hi"
let longer = @cmp.maximum_by_key(s1, s2, String::length)
inspect(longer, content="hello")

// Compare structs by a specific field
let alice = { name: "Alice", age: 25 }
let bob = { name: "Bob", age: 30 }
let younger = @cmp.minimum_by_key(alice, bob, p => p.age)
debug_inspect(
younger,
content=(
#|{ name: "Alice", age: 25 }
),
)

// When keys are equal, the first argument is considered the minimum
let p1 = ("first", 1)
let p2 = ("second", 1)
let snd = (p : (_, _)) => p.1
@debug.assert_eq(@cmp.minimum_by_key(p1, p2, snd), p1)
@debug.assert_eq(@cmp.maximum_by_key(p1, p2, snd), p2)
}

#
Reverse

pub(all) struct Reverse[T](T) derive(Eq, Hash,
Debug
)

A newtype wrapper that reverses the comparison order of the wrapped value.

Reverse[T] is useful when you need to reverse the natural ordering of a type. For example, to create a min-heap from a max-heap data structure, or to sort in descending order instead of ascending order.

Examples

test {
let a = @cmp.Reverse(1)
let b = @cmp.Reverse(2)
inspect(a.compare(b), content="1") // 1 > 2 in reversed order
inspect(b.compare(a), content="-1") // 2 < 1 in reversed order
inspect(a == a, content="true") // Equality works correctly
@debug.debug_inspect(a, content="Reverse(1)") // Shows wrapped value
}
impl Compare for Reverse[T]
impl Show for Reverse[T]

#
Reverse::compare

fn[T : Compare + Eq] Reverse::compare(a : Reverse[T], b : Reverse[T]) -> Int

#
Reverse::equal

fn[T : Eq] Reverse::equal(Reverse[T], Reverse[T]) -> Bool

#
Reverse::hash

fn[T : Hash] Reverse::hash(self : Reverse[T]) -> Int

#
maximum

fn[T : Compare + Eq] maximum(x : T, y : T) -> T

Compares and returns the maximum of two values.

Returns the second argument if the comparison determines them to be equal.

Examples

test {
inspect(@cmp.maximum(1, 2), content="2")
inspect(@cmp.maximum(2, 1), content="2")
let fst = []
let snd = []
@cmp.maximum(fst, snd).push(0)
debug_inspect(snd, content="[0]")
}

#
maximum_by_key

fn[T, K : Compare + Eq] maximum_by_key(x : T, y : T, f : (T) -> K) -> T

Returns the element that gives the maximum value from the specified function.

Returns the second argument if the comparison determines them to be equal.

Examples

test {
inspect(@cmp.maximum_by_key(1, -2, Int::abs), content="-2")
inspect(@cmp.maximum_by_key(-2, 1, Int::abs), content="-2")
inspect(@cmp.maximum_by_key(-2, 2, Int::abs), content="2")
}

#
minimum

fn[T : Compare + Eq] minimum(x : T, y : T) -> T

Compares and returns the minimum of two values.

Returns the first argument if the comparison determines them to be equal.

Examples

test {
inspect(@cmp.minimum(1, 2), content="1")
inspect(@cmp.minimum(2, 1), content="1")
let fst = []
let snd = []
@cmp.minimum(fst, snd).push(0)
debug_inspect(fst, content="[0]")
}

#
minimum_by_key

fn[T, K : Compare + Eq] minimum_by_key(x : T, y : T, f : (T) -> K) -> T

Returns the element that gives the minimum value from the specified function.

Returns the first argument if the comparison determines them to be equal.

Examples

test {
inspect(@cmp.minimum_by_key(1, -2, Int::abs), content="1")
inspect(@cmp.minimum_by_key(-2, 1, Int::abs), content="1")
inspect(@cmp.minimum_by_key(-2, 2, Int::abs), content="-2")
}

#
minmax

fn[T : Compare + Eq] minmax(x : T, y : T) -> (T, T)

Returns both the minimum and maximum of two values as a tuple.

Parameters:

  • x : The first value to compare.
  • y : The second value to compare.

Returns a tuple (min, max) where the first element is the smaller value and the second element is the larger value. If the values are equal, returns (x, y).

Examples:

test {
debug_inspect(@cmp.minmax(1, 2), content="(1, 2)")
debug_inspect(@cmp.minmax(2, 1), content="(1, 2)")
}

#
minmax_by_key

fn[T, K : Compare + Eq] minmax_by_key(x : T, y : T, f : (T) -> K) -> (T, T)

Returns the minimum and maximum of two values based on a comparison function.

Parameters:

  • x : The first value to compare.
  • y : The second value to compare.
  • f : A function that extracts a comparable key from each value.

Returns a tuple (min, max) where the first element is the value that produces the smaller key and the second element is the value that produces the larger key. If the keys are equal, returns (x, y).

Examples:

test {
debug_inspect(@cmp.minmax_by_key(1, -2, Int::abs), content="(1, -2)")
debug_inspect(@cmp.minmax_by_key(-2, 1, Int::abs), content="(1, -2)")
debug_inspect(@cmp.minmax_by_key(-2, 2, Int::abs), content="(-2, 2)")
}

Source Files