Is it possible to transpile Elixir into ReasonML/BuckleScript/JavaScript?

Elixir, OCaml and ReasonML are similar: functional and object-oriented friendly.

Is that possible to transpile Elixir into ReasonML/BuckleScript/JavaScript?

https://elixirscript.github.io/

But just like Elixir there is no static typing as you have with Bucklescript/ReasonML (and of course there are no “processes”).

2 Likes

Thanks @peerreynders.

Should Elixir add type system including type inference? Is that better?

1 Like

It’s unlikely to happen. However in Elixir (not Elixirscript) you can use success typing with dialyzer.

Types (or lack thereof)
Type Specifications

2 Likes

It’s not really the syntax that makes Elixir great, it’s the runtime, and neither OCaml nor JS have similar runtimes.

I think transpilation of a language into a radically different runtime is more trouble than it’s worth- you have to write your code completely different and there’s not really a lot of code sharing that actually happens between runtimes.

8 Likes

Couple of videos (on opinions) why transpiling from a sound to a loose language may be a good idea when we are talking about the JS eco-system.

With the BEAM matters are more difficult because of typing the contents of the process mailbox which is largely the result of dynamic sends and receives.

4 Likes

Transpiling Elixir into whatever is definitely possible and probably not too difficult, at least the sequential part of the language. However, without all the “systems stuff” like processes, concurrency, error handling, all the goodies in the BEAM, etc etc it is actually pretty useless. It is the system building parts of Erlang/Elixir which are the truly important parts and they are definitely the most difficult parts to implement.

8 Likes

Conceptually? Maybe. Elixir with static types would be something else, but it might end up nicer than the untypes version. But it wouldn’t be necessarily better.

On the other hand, it makes more sense to add static typing to the BEAM ecosystem than compiling elixir to a language with static types.

Adding static types to Elixir would be adding a useful compile-time feature to a great runtime.

Compiling Elixir to OCaml would be compiling a language with dynamic typing and a great runtime oprimized for concurrency and message passing into a runtime that knows little about concurrency and message passing…

In practice, you CAN’T “add static types to elixir”. You can weite a new programming language with static types with a syntax similar to Elixir, but anything with static types will no longer be Elixir… I’ve written about his somehwere else im this forum. I have to find it.

1 Like

This. I’m a huge OCaml buff (and C++), but the BEAM is what makes Elixir truly awesome, and Elixir is one of the best languages on the BEAM. :slight_smile:

That seems in general to me. Going from a sound language (like OCaml) to an unsound language (like JS or Elixir) is fairly easy, but going the other way is a slice of hell as you basically have to start wrapping everything up into a variant/sum type… >.<

I still say that trying to type the process mailbox is a fools errand, it should only be black boxed (a variant/sum type over all possible BEAM types) that has to be matched on to extract the information.

This is the important BEAM parts. OCaml will get similar things when it’s long-coming Multi-Core/Effects system comes out, but that is still an unbounded period into the future… ^.^;

I’d personally think it would be better. By having types you can write a lot less code (yay code generation based on types!), you can generate more efficient code (yay static protocols!), etc… etc… :slight_smile:

Being able to have the BEAM use some form of type annotations would allow it to generate more efficient machine code almost for free (once implemented of course), but that’s just a speed boon rather than a coding boon.

Exactly this. OCaml will know that stuff later with the MC/Effects update, but it absolutely does not at all right now.

Sure you can, Elixir’s macro system is well powerful enough to implement an entire Hindley-Milner typing system entirely in-macro’s. I wish I had the time to work on mine!!!

But still, just have any code it calls out to that is in an untyped chunk just force the user to match on (block-box it), fully backwards compatible and all. :slight_smile:

2 Likes

Well, this is a question of definitions… What exactly is “Elixir”? Is it a file such that, when fed to the elixir compiler, will run without errors (possibly outputing a valid BEAM module)?

If so, than almost anything is elixir… For example:

use BrainFuck

b"""
++++++++++[>++++++++>+++++++++++
>---------->+++>++++++++>+++++++
+++++>+++++++++++>++++++++++>+++
++++++++>+++<<<<<<<<<<-]>-.>--.>
++++.>++.>---.>---.>.>.>+.>+++.,
"""

or even

use OCaml

o"""
(* Binary tree with leaves car­rying an integer. *)
type tree = Leaf of int | Node of tree * tree

let rec exists_leaf test tree =
  match tree with
  | Leaf v -> test v
  | Node (left, right) ->
      exists_leaf test left
      || exists_leaf test right

let has_even_leaf tree =
  exists_leaf (fun n -> n mod 2 = 0) tree
"""

For the benefit of people following this discussion (you don’t need to be told this), of course you can implement a HM typesystem with macros. Macros are arbitrary functions that return an AST, so they can type the AST given as argument and add the types of top-level functions to a global registry. Something like:

defmodule TypedElixir do
  defmacro defmodule_typed(name, [do: body]) do
    typechecked = TypedElixir.Typechecker.typecheck_body(body)
    TypedElixir.Typechecker.add_to_global_registry(typechecked)
    processed = TypedElixir.Compiler.process(body)

    quote do
      defmodule unquote(name), do: processed
    end
  end
end

The problem is that this typed subset of Elixir would be so incompatible with the standard library that although it could be called Elixir, it would be in fact something else. You can reuse some of the specs from dyalizer (if you unify the type variables properly), but I doubt you can reuse even most of them (HM needs unique type constructors for different types, so even :ok/:error tuples are hard to type in a meaningful way.

Having worked on ElixirScript, I mostly agree with what @rvirding said. Thanks to the work that the Elixir Core Team put into Elixir 1.5 and Erlang 20, it is relatively easy to compile Elixir to another target. The useless part is almost correct. There are a lot of expectations. Most of them inside of the BEAM and ElixirScript fails to live up to those these days. The FFI though does allow one to treat it similarly to things like BuckleScript though.

All is not lost though. Any efforts to do anything of this sort should focus on the BEAM characteristics first.

8 Likes

Sounds like trying to define Lisp, but Typed Lisps (written in lisp macros) are still considered lisp. :slight_smile:

Why would it be incompatible? It is easy to define external typed definitions of things (which can of course be combined up for global access). :slight_smile:

Untyped could call typed, typed could call untyped (either by getting a variant/sum back or by typing the definition explicitly). ^.^

And dialyzer specs are a good start and can be extended pretty easily (which is what my experiment was doing, quite successfully), it would not be backwards compatible of course, but then again most code passed to a macro will fail to compile if you take it out of the macro so that’s not surprising in any case.

Yes, you can always define some typed wrappers (in both directions). My point is that it’s not easy to use the standard library. The main offender is the inconsistent use of :ok/:error tuples.

I’m not saying that this can’t be done! It’s just that there is this mismatch between typed and untyped code, which seems hard to deal with.

Converting typed code to untyped is easier :slight_smile:

Most difficulties of defining a lisp translate pretty well to defining Elixir. Where lisp has reader macros, elixir has sigils, which are pretty similar.

Yeah I really wish Elixir followed Erlang more closely on those… ^.^;

But a couple wrapper modules would ease stuff too (and those could still be used from untyped code as well!). :slight_smile:

How’s that quote go, something like Every language is getting closer to Lisp or something like that. ^.^

I don’t read much erlang, but my issue with Elixir tuples is that sometimes thy are equivalent to Haskell’s Maybe a(AKA Some/None) type and sometimes equivalent to Either a b (AKA Error/Ok). If these tuples were used consistently you could make them the concrete implementation of the data constructors for those types.

Yep, they are entirely just a runtime version of sum types when used as such, every time I use them I keep wishing for static typing to make it all unambiguous… >.>

1 Like

An erlang term is a runtime sum type in which the first bits are the concrete implementation of the type constructor xD unfortunately, it’s the only type available in the lamguage ahahah

1 Like

How about Greenspun’s Tenth Rule:

“Any sufficiently complicated C or Fortran program contains an ad-hoc, informally-specified, bug-ridden, slow implementation of half of Common Lisp.”

2 Likes

I believe having a good transpiler to JavaScript is valuable. Even without system stuffs like processes.

You can then turn Phoenix or other elixir web frameworks into more modern and powerful full-stack frameworks. Universal rendering, shared type and code, real-time subscriptions etc. Imagine a web-framework like Meteor with terrifying velocity but also having incredible scalability. It will become a power tool of beating the average.

Another example is ClojureScript, it is great and having a lot of wonderful libraries. And there are also people really using them.

ElixirScript can provide most of what you describe today. A transpiler that does not support processes, code sharing between front end and back end, an ffi, ability to create packages that can be placed in hex. If those are the goals, it’s pretty close. Could probably use more work in the user friendliness and doc departments though.

3 Likes