Skip to content

Releases: leostera/caramel

v0.1.1: Improvements to Docs, Better operator support, Cleaning up Stdlib

07 Mar 09:16
Choose a tag to compare

📙 Manual

  • The manual is now automatically released in CI through Github Actions.
  • We've got an open invite to Discord available on every page.
  • Erlang as a runtime dependency has been clarified.
  • Fixed several SEO issues.

🧰 Compiler

  • Better support for bit-shift, unary float, and keyword operators
  • Now support for floating point numbers without trailing digits (1. == 1.0)

📚 Standard Library

  • Introduced the Math module
  • Clean up several unimplemented bindings that were leftovers from the OCaml
    standard library

v0.1.0: Shaping up!

23 Jan 16:04
Choose a tag to compare

Read the Caramel Changelog

🌎 From a Backend to Language

Caramel is starting to take shape, and we'll now refer to it as a language
rather than an OCaml backend to make it a little easier to talk about it.

After all, it isn't really 100% OCaml but a strict subset of it. It doesn't
ship the same standard library or tools.

We also have a new website at:

🗫 Community

We've updated our Code of Conduct to the Contributor Covenant

We've opened the Github
drop by and say hi or grab a Discord invite link! 👋

📙 Manual

I've started work on the Caramel Manual where we
have an installation guide, an introduction, a small syntax cheatsheet, some
examples, and a small guide on writing Caramel code that talks to existing
Erlang code.

This is a big work in progress, so if you'd like to help, please reach out!

In the future I'm planning to write guides for how to use Caramel with existing
build systems like Rebar3 or Mix, and include a reference guide to the standard

💅 Caramel Formatter

Caramel now ships a formatter that you can run to make sure your code is always
stylish and you have no more bikesheds. It supports ZERO configuration, so what
you see is what you get.

This is currently just a wrapper around ocamlformat, and all the kudos go to
the amazing team putting that together.

You can use it by calling caramel fmt *.ml and it should work on both .ml
and .mli sources.

It only does in-place formatting.

🧰 Compiler

The compiler has dropped support for several targets, including Core Erlang to
Native, and the default OCaml compilation modes.

It will from now on focus only on taking Caramel sources into runnable Erlang
and Core Erlang code. Over time we will move from Erlang to only Core Erlang
support, to make it easier to reuse Caramel code from Erlang, Elixir, Gleam,
and Hamler.

The additions to the compiler are:

  • Replaced unbound vars in specs with wildcards (thanks @ilya-klyuchnikov, PR)
  • Keyword atoms are automatically quoted now
  • Removed unnecessary compilation steps (thanks @Drup)
  • Removed unused object file generation (.cmo)
  • Better support for operators like &&, ||, and >=

📚 Standard Library

The standard library has been simplified for contributing to it, and you can now
find it at the top of the repository.


  • String concatenation now possible with the ^ operator: "yay" ^ "!!!"
  • Binary.split/3 to split binary strings
  • Erlang.floor/1 to round down floats to integers
  • Erlang.list_to_float/1 to parse strings to floats
  • Erlang.float_to_list/1 to turn floats into strings
  • Erlang.list_to_integer/1 to parse strings to integers
  • Erlang.integer_to_list/1 to turn integers into strings
  • Lists.foldl/foldr signature has been fixed

v0.0.14: Website, split Erlang library, proper exit codes, and better runtime support

01 Nov 22:25
Choose a tag to compare


  • erlang: the Erlang library included, with a lexer/parser/AST/printer
    for Standard Erlang, is now completely split from the Caramel code and
    will be published to opam shortly.

  • caramelc: will return exit code 0 if everything went well. Otherwise
    expect a non-zero status!

  • stdlib: remove dependency on the Erlang AST printer for parts of the
    runtime (like the recv function), and instead include the relevant
    .erl sources as part of the packed stdlib.

  • docs: better contribution notes, documenting the release flow and
    saying a word about the rationale behind it. I've also put together a
    small website for Caramel here:

  • examples: the echo tcp server has been refactored to make it harder to
    accidentally override the gen_tcp module that is shipped with Erlang.
    We'll have to figure out a nice way to prevent these things from
    happening, which may just mean using all the modules on the Stdlib to
    avoid redefinition.

  • ci: several changes to CI to ensure we can release the erlang
    library to opam.

v0.0.13: Internal restructures preparing for OPAM publication

31 Oct 23:43
Choose a tag to compare

Not much, just a few internal refactors that aren't very interesting.

Next release tag will include a better changelog.

v0.0.12: First Milestone Completed!

30 Oct 19:37
Choose a tag to compare

Release Notes

This is the first actual release of Caramel that I'm making available 🎉

It includes 2 things:

  • caramelc, the Caramel compiler
  • erlang, an OCaml library for handling Erlang code, including an AST, lexer, parser, and printer

The Caramel compiler

Caramel can compile a large portion of the OCaml language, in particular most of the immutable functional OCaml, and into idiomatic Erlang code. Whenever possible it will look quite decent, and some times it will have pretty terrible formatting.

It runs as a single stand-alone binary with no dependencies (other than glibc or musl), and it should be blazing fast. Here's some benchmark results from the examples/ocaml_to_erlang.t folder:

Screenshot from 2020-10-30 23-08-04

The compiler also includes an additional target that may be of interest to those who want to dig into the compilation process: caramelc parse. This command will read Erlang and OCaml sources, and dump different ASTs of them. It was very useful to have around for testing purposes as well.

erlang library for OCaml

The Erlang library currently includes support for the vast majority of the Standard Erlang language, according to the grammar shipped with Erlang/OTP as of version 24.

It includes a series of modules to make it easy to construct Erlang programs from OCaml, as well as deconstruct them and operate on them.

A pretty printer is also included that right now is used within the Caramel compiler to generate the Erlang sources. It unfortunately still has some tiny remnants of Caramel logic in it, but they should be cleaned up in the near future and should not get in the way of more general usage of this library.


  • compiler: match expressions with cascading cases are not that
    straighforward to translate to Erlang and my gut tells me that doing the
    juggling here will get in the way of type-checking Erlang in the
    upcoming milestone, so this is forbidden as it is right now.

v0.0.11: Prelim. support for guards and printing OCaml ASTs

30 Oct 18:17
Choose a tag to compare


  • compiler: preliminary support for guards is added in this release.
    They are "safe" as long as you don't redefine any of the expected
    functions. There is no good way at the moment to prevent this from
    happening, but we could achieve it by essentially forbidding the use
    of the module name Erlang and requiring all guards to be fully
    qualified names.

    This still leaves us with the issue of compounded guard expressions.

    At the end of the day, we want a function is_valid_guard : expression -> bool
    that can traverse an arbitrary expression and tell us if it
    is or is not a valid guard based on the specification found at the
    Erlang docs

  • caramelc: the parse subcommand now can take a --lang and --tree
    parameters to print out the parse and typed trees for OCaml, as well
    as the parse tree of Erlang, and the parse tree of the result of
    compiling OCaml to Erlang.

    This is particularly useful for testing and understanding the AST
    translation, and will likely be used later on to see if the compile ->
    typecheck -> compile cycle yields the same inputs, and thus is an

v0.0.10: Record updates and lambda calls

29 Oct 23:18
Choose a tag to compare


  • Add support for record updates (see #23):
{ my_record with field = value }
My_record#{ field := value }
  • Add tests showing that lambda function calls are now working as expected and will be called with the right number of parameters:
let f () =
  let g () = 1 in
  g ()
f() ->
  G = fun () -> 1 end,

v0.0.9: Safer compilation and better error messages

23 Oct 08:32
Choose a tag to compare


  • compiler(#12): the compiler will now let you know when you're
    redefining a function on the OCaml side, which is not allowed on the
    Erlang side and stop compilation.

  • compiler(#16): shadowing bindings with let are (for) now unsupported
    on the OCaml side, which makes translation runtime safe. We won't see
    any more X = X + 1 on the Erlang side.

  • compiler(#15): to help with #16, priming of variables is now supported
    and translated to valid Erlang. We can write x' = x + 1 and it will
    translate to X_prime = X + 1.

  • compiler(#13): recursive let bindings within a function definition are
    now not supported since they don't have a direct Erlang equivalent and
    require runtime overhead.

  • error messages have been created for all of the above

Minor Stdlib changes

23 Oct 06:05
Choose a tag to compare
Minor Stdlib changes Pre-release


  • stdlib: fix name of Io module so Merlin can pick it up properly.


Thanks a lot to @seanhinde for playing opening issue #19 and working through the problems outlined there with me 🙌🏼

Almost ready for standalone usage :rocket:

22 Oct 13:13
Choose a tag to compare

Better releases

  • compiler: automatic function reference arities! As see in #10

  • compiler: We're ignoring all fresh type variables when translating to Dialyzer
    specs for now. More work will be done in #20

  • caramelc: caramelc compile now supports multiple --target flags,
    so you can compile both archives and Erlang sources at once.

  • caramelc: standard library will now by default be in the respective
    installation directory (respecting dune install conventions)

  • stdlib: Process.spawn/1 has been renamed to Process.make/1 until
    we have support for module attributes (see #21)

  • stdlib: Dropped top-level namespacing until we figure out how it can
    work best with .merlin

  • ci: several changes to release flow, including a nicer folder
    structure in the tarball

  • ci: entire codebase is instrumentabled by bisect_ppx now to start
    gathering coverage reports

  • erlang: removed an unused helper