Home > front end >  In fp-ts, how to compose 2 (or more) Ord instances
In fp-ts, how to compose 2 (or more) Ord instances

Time:10-25

Say I have a list of strings and I want to sort them first by string length and then alphabetically (so strings within the list with the same length are sorted alphabetically).

I already have ordString which can be used to sort alphabetically. I can make my own Ord instance for string length:

import * as S from 'fp-ts/string'
import * as N from 'fp-ts/number'
import * as Ord from 'fp-ts/Ord'

const ordString = S.Ord

const ordStringLength = pipe(N.Ord, Ord.contramap((s: string) => s.length))

If I want to use these Ords to sort my list I can call A.sort twice, but this seems wasteful:

import * as A from 'fp-ts/Array'

const sorted = pipe(listOfStrings, A.sort(ordString), A.sort(ordStringLength))

Is there a way I can compose the ordString and ordStringLength instances into a single instance that can be used in a single call to A.sort?

(this is a contrived example to demonstate my question; in reality the ordering is more complex and may involve combining several Ords)

CodePudding user response:

Ord has a Monoid instance, which can be used to do what you want; that is, first order with one Ord, then with another.

There's a pretty good example in the fp-ts docs

in short, you should be able to do

import { sort } from 'fp-ts/Array'
import { getMonoid } from 'fp-ts/Ord'
import { concatAll } from 'fp-ts/Monoid'

const M = getMonoid<string>
const byBothOrds = concatAll(M)([ordString, ordStringLength])
const sorted = sort(byBothOrds)(listOfStrings)

It should be fairly obvious how to add additional Ords to this, as you asked.

  • Related