-
Notifications
You must be signed in to change notification settings - Fork 26
Polymorphic variant for ordering #12
Comments
@texastoland mentioned the usefulness of the tags being public - maybe that was the reason? |
Yeah that's definitely one use, they're just more expressive in general. Polymorphic variants are type level variants, the constructor is available as a type: type equal_to = [ `equal_to ]
type greater_than = [ `greater_than ]
type less_than = [ `less_than ]
type ordering = [ equal_to | greater_than | less_than ] The subtyping is a really nice feature -- polymorphic variant values work anywhere that accepts that variant as a member of the set without any extra wrapping and conversion: type greater_than_equal = [ greater_than | equal_to ]
type less_than_equal = [ less_than | equal_to ]
let f: greater_than_equal -> unit = fun _ -> ()
let f': ordering -> unit = fun _ -> ()
let x = `greater_than
let y = f x
let z = f' x You can also have functions take open variants, or any variant as long as it has the given types. Think of type 'a ordering_a = [> ordering] as 'a
let z: ordering = `equal_to
let g: [> `less_than | `greater_than] -> unit = fun _ -> ()
let w = g x
let w' = g z You can also have lower bounds on variants, where the type given has to be a subtype of the variant. Here let h: [< ordering] -> unit = fun _ -> ()
let x': less_than_equal = `less_than
let _ = h x' You can also combine upper and lower bounds: let g': [< `less_than | `equal_to | `greater_than > `greater_than ] -> string = fun x ->
match x with
| `greater_than -> "greater"
| _ -> "not greater"
let z': less_than_equal = `less_than
let z'': greater_than_equal = `greater_than
let _ = g' z' (* doesnt compile *)
let _ = g' z'' The line with "doesnt compile" won't compile because the function is looking for any variant that contains no more than And you match on poly variants based on their subtypes with the let print_lte: less_than_equal -> string = function
| `less_than -> "less than"
| `equal_to -> "equal to"
let print_gte: greater_than_equal -> string = function
| `greater_than -> "greater than"
| `equal_to -> "equal to"
let print_ordering: ordering -> string = function
| #less_than_equal as lte -> print_lte lte
| #greater_than_equal as gte -> print_gte gte The argument in favor of ordinary variants is that there is not that relaxed restriction between constructor and variant. Constructors aren't first-class and type-level like poly variants, but the upside is that the constructor is tied to a specific variant. It's a tradeoff basically: type foo_toggle = On | Off
type bar_toggle = On | Off
let ff: foo_toggle -> unit = fun _ -> ()
let foo: bar_toggle = On
let _ = ff foo (* doesnt compile, not a foo_toggle *) But you can have your cake and eat it too by just wrapping your poly variant structures using either an abstract type deriving functor if you need it to be opaque or a singleton ordinary variant like this: type toggle = [ `on | `off ]
type foo_toggle = FooToggle of toggle
type bar_toggle = BarToggle of toggle
let ff: foo_toggle -> unit = fun _ -> ()
let foo: bar_toggle = BarToggle `on
let _ = ff foo (* doesnt compile, not a foo_toggle *) Poly variants are my favorite feature of Ocaml, you can write very expressive type-level code with them, I wouldn't be able to enforce much of any of the CSS and HTML spec from https://github.com/Risto-Stevcev/bs-declaredom at compile time without poly variants for example, |
Cool, thanks for the explanation! This all makes sense. |
@Risto-Stevcev I shared your answer 📰 |
Hi @Risto-Stevcev - first of all, thanks for making this library, it's great to have an un-opinionated base of core functionality like this to build on!
I just had a quick question on the
ordering
type https://github.com/Risto-Stevcev/bs-abstract/blob/master/src/interfaces/Interface.re#L130 . I was curious why it was implemented as a polymorphic variant, rather than just a normal variant liketype ordering = | LT | EQ | GT
. I didn't look at all the usages, but I was curious if making it polymorphic enabled some kind of functionality?The text was updated successfully, but these errors were encountered: