Created
March 2, 2020 02:16
-
-
Save gaku-sei/cab01e4e0c601b676e625afb12890b4c to your computer and use it in GitHub Desktop.
Playing with functors to create an elaborate Percentage module
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* 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