Using a "compare/cmp" function, Belt.Id confusion

I’m trying to write a function that returns the maximum value of an array given a comparator function. That’s one of those functions that returns -1 if the first parameter is less than the second, +1 if the first parameter is greater than the second, and 0 if they are the same. I can get it to work as shown below.

    type nonEmptyArray<'t> = NonEmptyArray(array<'t>)

    let make = xs =>
      switch xs {
      | [] => None
      | xs => xs->NonEmptyArray->Some
      }

    // Does not require a default/initial value because array has
    // at least 1 item. And will always return a meaningful result.
    let maxBy = (NonEmptyArray(n), cmp) => n->Js.Array2.reduce((maximum, i) =>
        if cmp(i, maximum) < 0 {
          maximum
        } else {
          i
        }
      , n[0])

This is pretty good, but I don’t like that my cmp function is not really documented anywhere. It’s just a function that takes two of something and returns an int. So I’m trying to reuse some well-defined comparer function type but can’t figure out how to do it. This doesn’t work…

    // SYNTAX ERROR
    type comparer<'t> = (~a:'t,~b:'t) => int
    let bigger<'t> = (a,b,cmp:comparer<'t>) =>
      if cmp(a,b)<0 {
        b
      }
      else {
        a
      }

I figure for many of my types I’ll define comparator/id modules - still a big confused what these things are - so I can use them in sets and maps. But I can’t figure out how to re-use the compare function built into these things.

    // SYNTAX ERROR
    module IntComparable = Belt.Id.MakeComparable({
      type t = int
      let cmp = (a, b) => Pervasives.compare(a, b)
    })
    let compareTwoIntegers = (a, b) => IntComparable.cmp(a, b)

This is a syntax error because there’s no such construct as let bigger<'t> in ReScript. Values don’t have type parameters (EDIT: not exactly true, but that’s an advanced topic), only types do.

module IntComparable = Belt.Id.MakeComparable({...

This is actually not a syntax error, it is a type error:

[E] Line 6, column 35:
This expression has type
    Belt_Id.cmp<IntComparable.t, IntComparable.identity>
  It is not a function.

The value IntComparable.cmp is an object of the abstract type Belt.Id | ReScript API , it can’t be called as a function. In fact normally it won’t be used directly, but passed into Belt Set, Map etc. constructor functions though: Belt.Set | ReScript API

let mySet = Belt.Set.make(~id=module(IntComparable))
let mySet2 = Belt.Set.add(mySet, 1)

I think the key point is that Belt’s comparator values actually don’t let you just directly use them to compare values, but only indirectly through Belt’s data structures.

We could use the Belt comparators with this snippet:

module IntComparable = Belt.Id.MakeComparable({
  type t = int
  let cmp = (a, b) => Pervasives.compare(a, b)
})

let cmp = Belt.Id.getCmpInternal(IntComparable.cmp)
let _ = cmp(. 1, 2)