mirror of
https://github.com/IBM/fp-go.git
synced 2025-08-10 22:31:32 +02:00
initial checkin
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
This commit is contained in:
37
ord/monoid.go
Normal file
37
ord/monoid.go
Normal file
@@ -0,0 +1,37 @@
|
||||
package ord
|
||||
|
||||
import (
|
||||
F "github.com/ibm/fp-go/function"
|
||||
M "github.com/ibm/fp-go/monoid"
|
||||
S "github.com/ibm/fp-go/semigroup"
|
||||
)
|
||||
|
||||
// Semigroup implements a two level ordering
|
||||
func Semigroup[A any]() S.Semigroup[Ord[A]] {
|
||||
return S.MakeSemigroup(func(first, second Ord[A]) Ord[A] {
|
||||
return FromCompare(func(a, b A) int {
|
||||
ox := first.Compare(a, b)
|
||||
if ox != 0 {
|
||||
return ox
|
||||
}
|
||||
return second.Compare(a, b)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// Monoid implements a two level ordering such that
|
||||
// - its `Concat(ord1, ord2)` operation will order first by `ord1`, and then by `ord2`
|
||||
// - its `Empty` value is an `Ord` that always considers compared elements equal
|
||||
func Monoid[A any]() M.Monoid[Ord[A]] {
|
||||
return M.MakeMonoid(Semigroup[A]().Concat, FromCompare(F.Constant2[A, A](0)))
|
||||
}
|
||||
|
||||
// MaxSemigroup returns a semigroup where `concat` will return the maximum, based on the provided order.
|
||||
func MaxSemigroup[A any](O Ord[A]) S.Semigroup[A] {
|
||||
return S.MakeSemigroup(Max(O))
|
||||
}
|
||||
|
||||
// MaxSemigroup returns a semigroup where `concat` will return the minimum, based on the provided order.
|
||||
func MinSemigroup[A any](O Ord[A]) S.Semigroup[A] {
|
||||
return S.MakeSemigroup(Min(O))
|
||||
}
|
166
ord/ord.go
Normal file
166
ord/ord.go
Normal file
@@ -0,0 +1,166 @@
|
||||
package ord
|
||||
|
||||
import (
|
||||
C "github.com/ibm/fp-go/constraints"
|
||||
E "github.com/ibm/fp-go/eq"
|
||||
F "github.com/ibm/fp-go/function"
|
||||
P "github.com/ibm/fp-go/predicate"
|
||||
)
|
||||
|
||||
type Ord[T any] interface {
|
||||
E.Eq[T]
|
||||
Compare(x, y T) int
|
||||
}
|
||||
|
||||
type ord[T any] struct {
|
||||
c func(x, y T) int
|
||||
e func(x, y T) bool
|
||||
}
|
||||
|
||||
func (self ord[T]) Equals(x, y T) bool {
|
||||
return self.e(x, y)
|
||||
}
|
||||
|
||||
func (self ord[T]) Compare(x, y T) int {
|
||||
return self.c(x, y)
|
||||
}
|
||||
|
||||
// MakeOrd creates an instance of an Ord
|
||||
func MakeOrd[T any](c func(x, y T) int, e func(x, y T) bool) Ord[T] {
|
||||
return ord[T]{c: c, e: e}
|
||||
}
|
||||
|
||||
// MakeOrd creates an instance of an Ord from a compare function
|
||||
func FromCompare[T any](compare func(T, T) int) Ord[T] {
|
||||
return MakeOrd(compare, func(x, y T) bool {
|
||||
return compare(x, y) == 0
|
||||
})
|
||||
}
|
||||
|
||||
// Reverse creates an inverted ordering
|
||||
func Reverse[T any](o Ord[T]) Ord[T] {
|
||||
return MakeOrd(func(y, x T) int {
|
||||
return o.Compare(x, y)
|
||||
}, o.Equals)
|
||||
}
|
||||
|
||||
// Contramap creates an odering under a transformation function
|
||||
func Contramap[A, B any](f func(B) A) func(Ord[A]) Ord[B] {
|
||||
return func(o Ord[A]) Ord[B] {
|
||||
return MakeOrd(func(x, y B) int {
|
||||
return o.Compare(f(x), f(y))
|
||||
}, func(x, y B) bool {
|
||||
return o.Equals(f(x), f(y))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Min takes the minimum of two values. If they are considered equal, the first argument is chosen
|
||||
func Min[A any](o Ord[A]) func(A, A) A {
|
||||
return func(a, b A) A {
|
||||
if o.Compare(a, b) < 1 {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
}
|
||||
|
||||
// Max takes the maximum of two values. If they are considered equal, the first argument is chosen
|
||||
func Max[A any](o Ord[A]) func(A, A) A {
|
||||
return func(a, b A) A {
|
||||
if o.Compare(a, b) >= 0 {
|
||||
return a
|
||||
}
|
||||
return b
|
||||
}
|
||||
}
|
||||
|
||||
// Clamp clamps a value between a minimum and a maximum
|
||||
func Clamp[A any](o Ord[A]) func(A, A) func(A) A {
|
||||
return func(low, hi A) func(A) A {
|
||||
clow := F.Bind2nd(o.Compare, low)
|
||||
chi := F.Bind2nd(o.Compare, hi)
|
||||
return func(a A) A {
|
||||
if clow(a) <= 0 {
|
||||
return low
|
||||
}
|
||||
if chi(a) >= 0 {
|
||||
return hi
|
||||
}
|
||||
return a
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func strictCompare[A C.Ordered](a, b A) int {
|
||||
if a < b {
|
||||
return -1
|
||||
} else if a > b {
|
||||
return +1
|
||||
} else {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
func strictEq[A comparable](a, b A) bool {
|
||||
return a == b
|
||||
}
|
||||
|
||||
// FromStrictCompare implements the ordering based on the built in native order
|
||||
func FromStrictCompare[A C.Ordered]() Ord[A] {
|
||||
return MakeOrd(strictCompare[A], strictEq[A])
|
||||
}
|
||||
|
||||
/**
|
||||
* Test whether one value is _strictly less than_ another
|
||||
*/
|
||||
func Lt[A any](O Ord[A]) func(A) func(A) bool {
|
||||
return func(second A) func(A) bool {
|
||||
return func(first A) bool {
|
||||
return O.Compare(first, second) < 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test whether one value is less or equal than_ another
|
||||
*/
|
||||
func Leq[A any](O Ord[A]) func(A) func(A) bool {
|
||||
return func(second A) func(A) bool {
|
||||
return func(first A) bool {
|
||||
return O.Compare(first, second) <= 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test whether one value is _strictly greater than_ another
|
||||
*/
|
||||
func Gt[A any](O Ord[A]) func(A) func(A) bool {
|
||||
return func(second A) func(A) bool {
|
||||
return func(first A) bool {
|
||||
return O.Compare(first, second) > 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test whether one value is greater or equal than_ another
|
||||
*/
|
||||
func Geq[A any](O Ord[A]) func(A) func(A) bool {
|
||||
return func(second A) func(A) bool {
|
||||
return func(first A) bool {
|
||||
return O.Compare(first, second) >= 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test whether a value is between a minimum (inclusive) and a maximum (exclusive)
|
||||
func Between[A any](O Ord[A]) func(A, A) func(A) bool {
|
||||
lt := Lt(O)
|
||||
geq := Geq(O)
|
||||
return func(lo, hi A) func(A) bool {
|
||||
// returns the predicate
|
||||
return P.And(lt(hi))(geq(lo))
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user