Skip to content

Instantly share code, notes, and snippets.

@gaku-sei
Created March 2, 2020 02:16
Show Gist options
  • Save gaku-sei/cab01e4e0c601b676e625afb12890b4c to your computer and use it in GitHub Desktop.
Save gaku-sei/cab01e4e0c601b676e625afb12890b4c to your computer and use it in GitHub Desktop.
Playing with functors to create an elaborate Percentage module
/* Comes from BsAbstract and Relude */
module type EQ = {type t; let eq: (t, t) => bool;};
type ordering = [ | `less_than | `equal_to | `greater_than];
module type ORD = {include EQ; let compare: (t, t) => ordering;};
module type BOUNDED = {include ORD; let top: t; let bottom: t;};
module type SHOW = {type t; let show: t => string;};
module EqInt: (EQ with type t = int) = {
type t = int;
let eq = (x, y) => x == y;
};
module OrdInt: (ORD with type t = int) = {
include EqInt;
let compare = (x, y) =>
if (x > y) {
`greater_than
} else if (x < y) {
`less_than
} else {
`equal_to
}
};
module BoundedInt: (BOUNDED with type t = int) = {
include OrdInt;
let top = Js.Int.max;
let bottom = Js.Int.min;
};
module ShowInt: (SHOW with type t = int) = {
type t = int;
let show = string_of_int;
};
module EqFloat: (EQ with type t = float) = {
type t = float;
let eq = (x, y) => x == y;
};
module OrdFloat: (ORD with type t = float) = {
include EqFloat;
let compare = (x, y) =>
if (x > y) {
`greater_than
} else if (x < y) {
`less_than
} else {
`equal_to
}
};
module BoundedFloat: (BOUNDED with type t = float) = {
include OrdFloat;
[@bs.val] external top : float = "Number.MAX_VALUE";
[@bs.val] external bottom : float = "Number.MIN_VALUE";
};
module ShowFloat: (SHOW with type t = float) = {
type t = float;
let show = Js.Float.toString;
};
/* Percentage module */
module Percentage = (B: BOUNDED, S: SHOW with type t = B.t): {
type t;
let make: B.t => t;
let show: t => string;
} => {
include B;
include (S : SHOW with type t := t);
let make = x => switch (compare(x, bottom)) {
| `less_than => bottom
| _ => switch (compare(x, top)) {
| `greater_than => top
| _ => x
}
};
};
module PercentageInt = Percentage(BoundedInt, ShowInt);
module PercentageFloat = Percentage(BoundedFloat, ShowFloat);
let p: PercentageInt.t = PercentageInt.make(30);
let f: PercentageInt.t => React.element = p =>
<div>
{p |> PercentageInt.show |> React.string}
</div>;
f(p); // Works!
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment