4

Is there a way to combine multiple variants together into one? Something like this:

type pet = Cat | Dog;
type wild_animal = Deer | Lion;
type animal = pet | wild_animal;

This is a syntax error, but I would like animal to become a variant with four constructors: Cat | Dog | Deer | Lion. Is there a way to do this?

Robz
  • 1,747
  • 5
  • 21
  • 35

2 Answers2

6

Polymorphic variants are created with exactly your idea in mind. They are less efficient as memory representation, but it shouldn't matter if you are going to compile it to JavaScript:

type pet = [ | `Cat | `Dog];
type wild_animal = [ | `Deer | `Lion];
type animal = [ pet | wild_animal ];
loxs
  • 1,476
  • 1
  • 12
  • 27
  • Your first paragraph iswrong: `type t = Cat type w = Cat` is perfectly valid in the same module. Moreover argumentless constructor are represented as simple integer in the runtime. – octachron Jun 10 '18 at 09:36
  • Alright, just removed the first paragraph, because the other answer explains it better. – loxs Jun 11 '18 at 07:15
  • I don't think polymorphic variants are less efficient. They just use a hash value instead counting up from 0. But Most of the time it makes no difference if you have {0, 1, 2, 3} or {45346, 464575678, 6354645674, 32542} as values for the variant. – Goswin von Brederlow Jun 11 '18 at 10:56
  • That is true when you don't use parameters with polymorphic variants. This changes when you do: https://dev.realworldocaml.org/runtime-memory-layout.html#polymorphic-variants-1 – loxs Jun 11 '18 at 12:27
5

I would like animal to become a variant with four constructors: Cat | Dog | Deer | Lion. Is there a way to do this?

You can not do that directly. That would mean that Cat has type pet, but also type wild_animal. This is not possible using normal variants, which always have a single type. This is however possible with polymorphic variants, as the other answer describes.

Another solution, more common (but it depends on what you are trying to achieve), is to define a second layer of variants:

type pet = Cat | Dog
type wild_animal = Deer | Lion
type animal = Pet of pet | Wild_animal of wild_animal

That way, Cat has type pet, but Pet Cat has type animal.

Étienne Millon
  • 3,018
  • 11
  • 27
  • Ah clever! For those not familiar with regular ocaml syntax, the last statement there is `type animal = Pet(pet) | Wild_animal(wild_animal)` in reason – Robz Aug 27 '18 at 00:53