Hacker News new | ask | show | jobs
by wcrichton 3491 days ago
This is awesome, and a big step forward for OCaml. Only criticism is that it seems difficult/awkward that you need different functions/values for each phase. In other staged macro systems (Scala/LMS, Rust/Compiler Plugins) you can refer to the same functions in any phase, and you can also splice values from the staging phase into the runtime phase without explicit use of a function like Expr.of_int.
4 comments

There are some difficulties with moving arbitrary values between phases: it's easy to move an int or a list, but what about a mutable reference or a closure?

However, I don't think this will ultimately be a problem in practice, for two reasons. First, global values can be used in different phases via "module lifting". Second, there's a separate proposal for adding overloading to OCaml in the form of modular implicits:

https://www.cl.cam.ac.uk/~jdy22/papers/modular-implicits.pdf

Modular implicits will make it possible to use a single overload function ('lift', say) in place of a family of functions 'Expr.of_int', 'Expr.of_float', etc., which will make things much less awkward. And it's only a small step from there to having 'lift' called implicitly/automatically at appropriate points. Here's a message from an earlier discussion with a few more details:

https://sympa.inria.fr/sympa/arc/caml-list/2015-05/msg00032....

> There are some difficulties with moving arbitrary values between phases: it's easy to move an int or a list, but what about a mutable reference or a closure?

Wasn't this already answered by "Closing the Stage" [1]?

[1] http://lambda-the-ultimate.org/node/2575

"Closing the Stage" is about a different interaction between staging and closures: that (with some care) staging constructs can be elaborated into closures in an unstaged calculus.

The problem with moving arbitrary values between phases with macros is that values can refer to bits of the runtime environment that cease to exist when compilation is finished.

> that (with some care) staging constructs can be elaborated into closures in an unstaged calculus.

Exactly, which seems to provide the necessary semantics for references that you mentioned. Clarifying staging semantics for difficult abstractions like refs by elaboration into well understood closure semantics was the point of the paper.

Hasn't this matter been addressed years ago?

http://www.cs.utah.edu/plt/publications/macromod.pdf

This sounds very handy and I definitely need to learn more about LMS and Compiler Plugins. I wonder then what are the limitations on the values you can pass automatically across phases, since there must be (you cannot transfer e.g. a file handle from compile-time to run-time).
As far as I understand, for LMS: Those types T for which one has implemented needed operations for the Rep[T] type.

Shameless plug: For another comparison of MetaOCaml, LMS, Terra and AnyDSL (our approach) under the lens of staging/partial evaluation see our paper from GPCE'15: http://www.cdl.uni-saarland.de/papers/gpce15.pdf

Hello,

I work on lms and we are preparing a new version where Rep is implemented as a typeclass instead of a monad. It's much more pleasant because you manipulate IR.Int and scala.Int. So with the proper import you actually handle IR.Int so you're staged code is no different than a normal code.

I also agree that there seems to be too much separation between the phases. I wonder if this is a design choice or a design limitation. MetaOCaml also requires explicit lifting/unlifting of values.
There are certainly some design choices here. I want to emphasize that in the few projects where I've used macros (e.g. https://github.com/OlivierNicole/macros-examples), I found that these translating functions were scarcely needed and I never had to pass a non-standard type between phases.

You may want to read this comment which I find relevant: https://www.reddit.com/r/ocaml/comments/5e8slg/bringing_type...