on the BEAM

Leandro  

Developer @ Erlang Solutions

Started working on Caramel

around early September,

as an experiment.

 

Why is it so hard to

type-check Erlang?

I had the idea to start with a language that was already well-typed and cram it into Erlang.

 

The thesis?

 

The resulting subset of Erlang is also well-typed.

What should this well-typed language look like?

  • Should be functional, and have good support for BEAM idioms like recursion and pattern matching
     
  • Should be type safe, so if your program compiles you know there will be no runtime crashes because of data in the wrong shape or type
     
  • Should have an expressive type system, so we can use the types to really help us build better software
     
  • Should be already mature and heavily used in the industry
  • Is functional: it supports many of the things we do on the BEAM, and adds a few more (like currying, and exhaustive pattern matching)
     
  • Is type safe: and what's more, it has one of the best type-inferences in the world, so you don't even have to write the types most of the time
     
  • It has an expressive type system: so expressive that it is used a lot for making other programming languages, like the original version of Rust.
     
  • >26 years old and millions of industry+research hours put into it: It's been around since 1994 and it's been used in anything from web apps (original React.js, Ahrefs, Messenger.com), to financial industry (Jane Street), to theorem provers (Coq), type-checkers (FlowType), etc.

To give us its benefits, OCaml sets some constraints:

  1. OCaml doesn't allow code-reloading, so the resulting Erlang code should not be reloaded to guarantee it is still type-safe.
     
  2. In OCaml every term must have a known type, so Erlang code that is "too dynamic" will not be known to be well-typed.
     
  3. OCaml does not have Receive expressions, so we will have to add support somehow.

My first attempts were small programs.

Then came in some more complex state machines. In this case look at the phantom type of the state indicating its validity through the abstract types "valid" and "invalid". 

So far these attempts had been typing code in a single process...

...could this scale to multiple processes?

Assuming that there is no code reloading, and that we know the exact type of messages that a process can receive, we can limit the "send" function to only allow messages of the type a process is known to receive.

It goes without saying, this is not a new discovery, and there exists plenty of research on the subject that I'm still getting familiar with!

type 'a t
(** The type of channels *)

(** ... *)

val send : 'a t -> 'a -> unit
(** [send c v] sends the values [v] over the channel [c]. If the channel buffer
 * is full then the sending domain blocks until space becomes available. *)
 
(** ... *)

How do we know what type of messages a process can receive?

By observing what are the types of messages the receive expression is expected to return, we can build up the type of messages that this process can handle. 

f() ->
  receive 
    {ok, Number} -> Number + 1
  end.
let f recv = 
  match recv ~timeout:Infinity with 
  | `Ok number -> number + 1

Because number is being added to 1, and it came from the Ok tuple, then the receive expression must return values of type:

[ `Ok of int ] (** ok tuples with an integer *)

recv is expected to return:

[ `Add of int 
| `Hello of string
| `Reset 
]

3 process types:
 

"a", can receive messages of type [ `Call (int pid, int) ]

 

"b", can receive messages of type int (just numbers, not much)

 

"c", can receive messages of type bool

It looked like I could successfully compile a strict subset of OCaml right into somewhat idiomatic Erlang that seemed to work!

The next step was right on the nose.
 

If I can go from OCaml to Erlang,
can I come back from Erlang to OCaml while preserving this type information?

For a strict subset of Erlang,

it seems that we can!

OCaml to Erlang Compilation

Typechecking Erlang as OCaml

What's Next

Still a lot of research to be done in the area, but the results so far look promising.

I'm continuing to work with a lot of energies, thanks to

  • mentorship and encouragement from both communities (shoutout to Erik Schön, Stavros Aronis, Robert Virding, Drup, Octachron, Pontus Nagy, Ulrik Strid, and Rudi Grinberg)
     
  • the sponsorship of awesome people on Patreon and Github
     
  • your contributions! (if you'd like to help please reach out :), file issues)

Milestone 1

Sound Compilation

Milestone 2

Thank you!

OCaml​ on the BEAM

By Leandro Ostera

OCaml​ on the BEAM

Understanding how to build a type-checker for Erlang, I ended up building a compiler from OCaml to Erlang: Caramel.

  • 921