One of the things that I would use most often is just case matching, take this variant in OCaml:
type blah =
| Blorp
| Bleep of int
We can use it like this convoluted example:
let a = Blorp
let b = function
| Blorp -> 42
| Bleep i -> i
let b_app = b a
(Notice still no types specified?)
This will work as expected, b will be 42
. 
However, as development continues, this variant is used all over, I find out I need to change Blorp to hold an argument too, so I change the variant to:
type blah =
| Blorp of float
| Bleep of int
Oh no, a compile error!
Line 5, 8: Error: The constructor Blorp expects 1 argument(s),
but is applied here to 0 argument(s)
Where the similar thing in Elixir (using tagged tuples or structs or whatever) will silently just keep working, breaking existing code.
Or if I wanted to add a case instead of change one, say to this:
type blah =
| Blorp
| Bleep of int
| Bloop of float
I now get this at compile-time:
Line 8, characters 8-55:
Error 8: this pattern-matching is not exhaustive.
Here is an example of a value that is not matched:
Bloop _
(I compile with many warnings as errors)
So I need to add that case, or I need to add a default case (_ -> whatever
, like in Elixir/Erlang), but this makes me look at all the use-sites of it to see if anything else needs changing, things remain ‘safe’, and yet I’ve still not typed anything beyond making the original variant type itself. ^.^
However, what if I need to handle arbitrary variants, where I do not know what they all can be ahead of time and user-code could add their own, say as in a plug-in system! Well that is trivial in OCaml too:
let c = `Vwoop
let d = function
| `Vwoop -> 42
let d_app = d c
(The `
marks a polymorphic variant)
Here this match call accepts any polymorphic variant with the name Vwoop
with no args, however it will error at compile-time if you pass in something else, like this:
let c = `Dwoop
let d = function
| `Vwoop -> 42
let d_app = d c
This causes this error:
Line 16, 14: Error: This expression has type [> `Dwoop ]
but an expression was expected of type [< `Vwoop ]
The second variant type does not allow tag(s) `Dwoop
Here you can also see how types are inferred, it is saying that the expression will pass in a `Dwoop
but potentially open to more types in the future, and the function is accepting any polymorphic variant including `Vwoop
or less, however the `Dwoop
is not in the allowed list of `Vwoop
, but we can fix that with a default:
let c = `Dwoop
let d = function
| `Vwoop -> 42
| _ -> 0
let d_app = d c
This works, and you can pass in any type, user-defined, any arguments, etc… These are great for event callbacks of arbitrary events for example, handle what you want, ignore the rest, all fully and entirely type-safe with minimal code. 
Nicely enough, a polymorphic variant in OCaml is like a tagged tuple in Elixir/Erlang, even implemented the same way, `Vwoop
would be :Vwoop
in Elixir, and `Vwoop 42
would be {:Vwoop, 42}
in Elixir. ^.^
OCaml also has when
expressions, just like Elixir, so you could make the above b
be this for example:
let b = match a with
| Blorp -> 42
| Bleep i when i > 0 -> i
| Bleep i -> -i
Doing the same in Elixir means using something like the disc_union
library, which gives you a new ‘case’ that operates over a defined set of variants, but there is no polymorphic variant support. Thus you basically get a lot of code generated ‘for free’ just be virtue of the type system existing (even though you do not specify types, it can infer them, or will complain if it cannot, which almost never happens). This saves substantially on code, thus making it shorter and more readable, fully type safe, and saves substantially on maintenance later.
And of course you can turn those above errors to warnings if you want to ‘iteretively’ add things later but still have it yell at you but be successful (Match_failure at run-time then, which is identical to Elixir’s MatchError). ^.^
Now as for generating ‘new’ code, that is the domain of PPX’s in OCaml (think Macro in Elixir, bit more difficult to write, but technically a lot more powerful, its more like a token macro if one existed in the elixir world), and as an example yes, there is a JSON generator as one example (well more than one, I’ll use yojson here as it is the one I am most familiar with and is the most used one in OCaml, like poison in Elixir, but faster and more powerful, I’ll show how it can work on a variety of types here):
type an_integer = int [@@deriving yojson]
type a_string = string [@@deriving yojson]
type a_record_object = {
a_string : string;
an_integer : int;
} [@@deriving yojson]
type non_derived_record = { blah : string }
type a_variant =
| Blah
| Blorp of a_record_object
| Bloop of non_derived_record
[@@deriving yojson]
And this ppx will generate two functions per each of the tagged types, so for the a_variant
type it will generate two functions with the type signatures of:
val a_variant_of_yojson : Yojson.Safe.json -> (a_variant, string) Result.result
val a_variant_to_yojson : a_variant -> Yojson.Safe.json
So it gives you a convert to and a convert from. The convert to the type returns a result of that type or a string containing the parse error. It will recurse through the type as necessary to build up everything in a fully type safe way or it will give you a good parse error. You can also derive from to_yojson
or of_yojson
instead of just yojson
to get only one or the other function instead of both. You can add other tags (tags themselves are not PPX’s, the PPX’s can work over the file and this one just happens to look for tags to do its work, very LISP’y in power) to key things like in the doc examples:
type geo = {
lat : float [@key "Latitude"];
lon : float [@key "Longitude"];
}
[@@deriving yojson]
That way the json key types do not have to match the type name, and there are others to handle encoding, put a default for if it does not exist, etc… etc… You can of course use raw yojson methods to parse into or out of json manually, but if you have a set schema then this makes it trivial to safely parse out a json to exactly what it should be, try that with Elixir’s Poison. 