Code Monkey home page Code Monkey logo

caramel's Introduction

🍬 Caramel

An Erlang backend to the OCaml compiler

What is Caramel?

Caramel is an experimental project, featuring primarily an Erlang backend to the OCaml compiler, that brings one of the most mature and expressive type-systems in the world to the BEAM.

In short, it lets you write some OCaml:

(* math.ml *)
let inc x = x + 1

and it will compile it to Erlang.

% math.erl
-module(math).
-export([inc/1]).
inc(X) -> erlang:'+'(X, 1).

NOTE: idiomatic support for infix operators is still not there :)

Read more about the current and future goals in the roadmap.

Getting started

You can download the latest pre-release from the releases page. After unpacking it you should be able to add it to your PATH env and start playing around with the caramelc binary.

Like this:

# in this example I'm running linux with glibc
$ wget https://github.com/AbstractMachinesLab/caramel/releases/download/v0.0.12/caramel-v0.0.12-x86_64-unknown-linux-gnu.tar.gz
$ tar xzf caramel-*
$ export PATH=$(pwd)/caramel/bin

Now we can do a quick test:

$ echo 'let hello () = "world"' > hello_world.ml
$ caramelc compile hello_world.ml
Compiling hello_world.erl       OK
$ erl
Erlang/OTP 23 [erts-11.0.3] [source] [64-bit] [smp:64:64] [ds:64:64:10] [async-threads:1] [hipe]

Eshell V11.0.3  (abort with ^G)
1> c(hello_world).
{ok,hello_world}
2> hello_world:hello().
<<"world">>

To make use of the entire standard library you'll have to run erlc to compile it:

# after unzipping
$ erlc ./caramel/lib/caramel/stdlib/beam/*.erl
$ erl -pa ./caramel/lib/stdlib/beam
Erlang/OTP 23 [erts-11.0.3] [source] [64-bit] [smp:64:64] [ds:64:64:10] [async-threads:1] [hipe]

Eshell V11.0.3  (abort with ^G)
1> caramel_runtime:binary_concat(<<"hello, ">>, <<"world!">>).
<<"hello, world!">>

Examples

You can find several examples in ./examples, and in ./tests/compiler.

In the examples, you can run caramelc compile *.ml to get them all built in the right order.

Here's an OCaml module and the compiled Erlang module:

type msg = [ `Reset | `Add of int | `Hello of string ]

type state = string * int

let handle_message : state -> msg option -> state =
 fun state msg ->
  let x, y = state in
  match msg with
  | Some `Reset -> ("", 0)
  | Some (`Add z) -> (x, z)
  | Some (`Hello n) -> (n, y)
  | None -> state

let rec loop ~recv state =
  Io.format "current_state: ~p\n" [ state ];
  let msg = recv ~timeout:(Process.Bounded 5000) in
  let state2 = handle_message state msg in
  loop ~recv state2

let start x = Process.make (fun _self recv -> loop ~recv x)

let do_work () =
  let pid = start ("hi", 0) in
  Erlang.send pid (`Hello "joe")
% Source code generated with Caramel.
-module(holder_annotated).
-export_type([msg/0]).
-export_type([state/0]).

-export([do_work/0]).
-export([handle_message/2]).
-export([loop/2]).
-export([start/1]).

-type msg() :: reset
             | {add, integer()}
             | {hello, binary()}
             .

-type state() :: {binary(), integer()}.

-spec handle_message(state(), option:t(msg())) -> state().
handle_message(State, Msg) ->
  {X, Y} = State,
  case Msg of
    {some, reset} -> {<<"">>, 0};
    {some, {add, Z}} -> {X, Z};
    {some, {hello, N}} -> {N, Y};
    none -> State
  end.

-spec loop(fun((process:after_time()) -> option:t(msg())), state()) -> ok.
loop(Recv, State) ->
  io:format(<<"current_state: ~p\n">>, [State | []]),
  Msg = Recv({bounded, 5000}),
  State2 = handle_message(State, Msg),
  loop(Recv, State2).

-spec start(state()) -> erlang:pid(msg()).
start(X) -> process:make(fun
  (_self, Recv) -> loop(Recv, X)
end).

-spec do_work() -> ok.
do_work() ->
  Pid = start({<<"hi">>, 0}),
  erlang:send(Pid, {hello, <<"joe">>}).

Running on the Erlang shell we get this output:

examples/processes λ erl
Erlang/OTP 23 [erts-11.0.3] [source] [64-bit] [smp:64:64] [ds:64:64:10] [async-threads:1] [hipe]

Eshell V11.0.3  (abort with ^G)
1> c(holder_annotated).
{ok,holder_annotated}
2> holder_annotated:
do_work/0         handle_message/2  loop/2            module_info/0
module_info/1     start/1
2> holder_annotated:do_work().
current_state: {<<"hi">>,0}
{hello,<<"joe">>}
current_state: {<<"joe">>,0}
current_state: {<<"joe">>,0}
3>
BREAK: (a)bort (A)bort with dump (c)ontinue (p)roc info (i)nfo
       (l)oaded (v)ersion (k)ill (D)b-tables (d)istribution

caramel's People

Contributors

leostera avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.