caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* [Caml-list] Problems with printing MetaOCaml generated code
@ 2015-04-30 18:36 Ömer Sinan Ağacan
  2015-04-30 19:52 ` Jacques Carette
  0 siblings, 1 reply; 23+ messages in thread
From: Ömer Sinan Ağacan @ 2015-04-30 18:36 UTC (permalink / raw)
  To: OCaml Mailing List

Hi all,

I'm working on a MetaOCaml program and I want to save generated programs to
files instead of directly running them within the same program using
`Runcode.(.!)` or `Runcode.run`. The problem is MetaOCaml never prints
generated code, it's always failing with `Warning 22: The CSP value is a
closure or too deep to serialize`.

I can't see anything related in it's web page:
http://okmij.org/ftp/ML/MetaOCaml.html. What I understand from that page is
once I have a closed code, I should be able to print it no matter what.
However in my experience even the simplest realistic MetaOCaml program fails to
generate the code because of this error I mentioned above.

(One thing to note here is that my program generates the code on a couple of
inputs, but fails in most of them with this error message.)

In "Many ways to run the code" section it's said that "Since closed code is
essentially OCaml AST, after closing the generated code, the user may examine
and `run' it in many ways. One way of running the code is printing it." and
then it lists some API functions for printing. In my experience none of them
really work, I have closed code which I successfully closed using
`Runcode.close_code`, but `print_closed_code` is still failing with the error,
and `print_code_as_ast` is printing something that definitely doesn't look like
an AST for any imaginable programming language.(okay... I might have
exaggerated a bit, but it's definitely not OCaml AST and it contains some
references to generator program source, like "Generator.ml[248]" for example)

One relevant thing I could find in the documentation is this: "If the code
includes CSP only as literals or external references (and any code can be
arranged that way), the code can be stored into a file and then passed to
ocamlopt." If we remove this sentence from the documentation, I don't think it
mentions about any possible failures in code printing.

So now that I've expressed my frustration about this, I guess my main question
is: In what cases does MetaOCaml prints generated code? In what cases it
doesn't? Note that it fails to generate code even after calling
`print_closed_code (close_code ...)`, so being closed or not doesn't seem very
relevent here. Is this a bug in MetaOCaml? Are there any workarounds? Any ideas
what am I doing wrong?

Thanks in advance for any answers,

Ömer

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [Caml-list] Problems with printing MetaOCaml generated code
  2015-04-30 18:36 [Caml-list] Problems with printing MetaOCaml generated code Ömer Sinan Ağacan
@ 2015-04-30 19:52 ` Jacques Carette
  2015-04-30 20:25   ` Ömer Sinan Ağacan
  0 siblings, 1 reply; 23+ messages in thread
From: Jacques Carette @ 2015-04-30 19:52 UTC (permalink / raw)
  To: Ömer Sinan Ağacan, OCaml Mailing List

You will have some difficulties printing complex closures, especially 
when they refer to values built in the generator (CSPs) which are not 
simple values (strings, integers, etc).

Sometimes, very simple changes to the generator can allow closures and 
CSPs to be printable or not -- without very specific examples, I can't 
help (it's been a few years since I dug into this deeply).

I have been able to print rather complex, large codes with metaocaml.  
But one has to structure the generator rather carefully to ensure this 
possibility.

Jacques

On 2015-04-30 14:36 , Ömer Sinan Ağacan wrote:
> Hi all,
>
> I'm working on a MetaOCaml program and I want to save generated programs to
> files instead of directly running them within the same program using
> `Runcode.(.!)` or `Runcode.run`. The problem is MetaOCaml never prints
> generated code, it's always failing with `Warning 22: The CSP value is a
> closure or too deep to serialize`.
>
> I can't see anything related in it's web page:
> http://okmij.org/ftp/ML/MetaOCaml.html. What I understand from that page is
> once I have a closed code, I should be able to print it no matter what.
> However in my experience even the simplest realistic MetaOCaml program fails to
> generate the code because of this error I mentioned above.
>
> (One thing to note here is that my program generates the code on a couple of
> inputs, but fails in most of them with this error message.)
>
> In "Many ways to run the code" section it's said that "Since closed code is
> essentially OCaml AST, after closing the generated code, the user may examine
> and `run' it in many ways. One way of running the code is printing it." and
> then it lists some API functions for printing. In my experience none of them
> really work, I have closed code which I successfully closed using
> `Runcode.close_code`, but `print_closed_code` is still failing with the error,
> and `print_code_as_ast` is printing something that definitely doesn't look like
> an AST for any imaginable programming language.(okay... I might have
> exaggerated a bit, but it's definitely not OCaml AST and it contains some
> references to generator program source, like "Generator.ml[248]" for example)
>
> One relevant thing I could find in the documentation is this: "If the code
> includes CSP only as literals or external references (and any code can be
> arranged that way), the code can be stored into a file and then passed to
> ocamlopt." If we remove this sentence from the documentation, I don't think it
> mentions about any possible failures in code printing.
>
> So now that I've expressed my frustration about this, I guess my main question
> is: In what cases does MetaOCaml prints generated code? In what cases it
> doesn't? Note that it fails to generate code even after calling
> `print_closed_code (close_code ...)`, so being closed or not doesn't seem very
> relevent here. Is this a bug in MetaOCaml? Are there any workarounds? Any ideas
> what am I doing wrong?
>
> Thanks in advance for any answers,
>
> Ömer
>


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [Caml-list] Problems with printing MetaOCaml generated code
  2015-04-30 19:52 ` Jacques Carette
@ 2015-04-30 20:25   ` Ömer Sinan Ağacan
  2015-04-30 20:57     ` Ömer Sinan Ağacan
  0 siblings, 1 reply; 23+ messages in thread
From: Ömer Sinan Ağacan @ 2015-04-30 20:25 UTC (permalink / raw)
  To: Jacques Carette; +Cc: OCaml Mailing List

Thanks for the answer.

My main problem is not that some generated code are not printable -- rather,
it's not clear at all when a code is not printable. Now I have to play around
with code until suddenly it's printable...

Certainly not all code is printable even in theory, for example, what happens
if my generated code captures a file handle from code generator? Or a heap
object that's completely opaque to runtime system.(no type information etc.) In
those cases it may be possible to directly run the code but it's not possible
to print it.

But IMHO MetaOCaml should have done a better job at reporting those. Or at
least at least documenting when it's not possible.

I guess I have to play around and see if some of my random changes make it
printable.

---
Ömer Sinan Ağacan
http://osa1.net


2015-04-30 15:52 GMT-04:00 Jacques Carette <carette@mcmaster.ca>:
> You will have some difficulties printing complex closures, especially when
> they refer to values built in the generator (CSPs) which are not simple
> values (strings, integers, etc).
>
> Sometimes, very simple changes to the generator can allow closures and CSPs
> to be printable or not -- without very specific examples, I can't help (it's
> been a few years since I dug into this deeply).
>
> I have been able to print rather complex, large codes with metaocaml.  But
> one has to structure the generator rather carefully to ensure this
> possibility.
>
> Jacques
>
>
> On 2015-04-30 14:36 , Ömer Sinan Ağacan wrote:
>>
>> Hi all,
>>
>> I'm working on a MetaOCaml program and I want to save generated programs
>> to
>> files instead of directly running them within the same program using
>> `Runcode.(.!)` or `Runcode.run`. The problem is MetaOCaml never prints
>> generated code, it's always failing with `Warning 22: The CSP value is a
>> closure or too deep to serialize`.
>>
>> I can't see anything related in it's web page:
>> http://okmij.org/ftp/ML/MetaOCaml.html. What I understand from that page
>> is
>> once I have a closed code, I should be able to print it no matter what.
>> However in my experience even the simplest realistic MetaOCaml program
>> fails to
>> generate the code because of this error I mentioned above.
>>
>> (One thing to note here is that my program generates the code on a couple
>> of
>> inputs, but fails in most of them with this error message.)
>>
>> In "Many ways to run the code" section it's said that "Since closed code
>> is
>> essentially OCaml AST, after closing the generated code, the user may
>> examine
>> and `run' it in many ways. One way of running the code is printing it."
>> and
>> then it lists some API functions for printing. In my experience none of
>> them
>> really work, I have closed code which I successfully closed using
>> `Runcode.close_code`, but `print_closed_code` is still failing with the
>> error,
>> and `print_code_as_ast` is printing something that definitely doesn't look
>> like
>> an AST for any imaginable programming language.(okay... I might have
>> exaggerated a bit, but it's definitely not OCaml AST and it contains some
>> references to generator program source, like "Generator.ml[248]" for
>> example)
>>
>> One relevant thing I could find in the documentation is this: "If the code
>> includes CSP only as literals or external references (and any code can be
>> arranged that way), the code can be stored into a file and then passed to
>> ocamlopt." If we remove this sentence from the documentation, I don't
>> think it
>> mentions about any possible failures in code printing.
>>
>> So now that I've expressed my frustration about this, I guess my main
>> question
>> is: In what cases does MetaOCaml prints generated code? In what cases it
>> doesn't? Note that it fails to generate code even after calling
>> `print_closed_code (close_code ...)`, so being closed or not doesn't seem
>> very
>> relevent here. Is this a bug in MetaOCaml? Are there any workarounds? Any
>> ideas
>> what am I doing wrong?
>>
>> Thanks in advance for any answers,
>>
>> Ömer
>>
>

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [Caml-list] Problems with printing MetaOCaml generated code
  2015-04-30 20:25   ` Ömer Sinan Ağacan
@ 2015-04-30 20:57     ` Ömer Sinan Ağacan
  2015-04-30 21:35       ` Jeremy Yallop
  2015-05-01 11:21       ` oleg
  0 siblings, 2 replies; 23+ messages in thread
From: Ömer Sinan Ağacan @ 2015-04-30 20:57 UTC (permalink / raw)
  To: OCaml Mailing List

Let's talk on an example:

-- contents of TestData.ml
  type foo = Foo of int

-- contents of main
  open TestData

  let global_ref : int ref = ref 0

  let gen_inc =
    .< let _ = global_ref := !global_ref + 1 in () >.

  let gen_read =
    .< !global_ref >.

  let gen_write i =
    .< match i with
       | Foo i -> global_ref := i
     >.

  let gen_cls_wrt cls =
    .< global_ref := cls () >.

  let f_toplevel () = Random.int 10

  let _ =
    print_string "\n----------------------------\n";
    let _ = Print_code.print_code Format.std_formatter gen_inc in
    print_string "\n----------------------------\n";
    let _ = Print_code.print_closed_code Format.std_formatter
(Runcode.close_code gen_inc) in
    print_string "\n----------------------------\n";
    let _ = Print_code.print_closed_code Format.std_formatter
(Runcode.close_code (gen_write (Foo 10))) in
    print_string "\n----------------------------\n";
    let _ = Print_code.print_closed_code Format.std_formatter
(Runcode.close_code gen_read) in
    print_string "\n----------------------------\n";
    let f () = Random.int 10 in
    let _ = Print_code.print_closed_code Format.std_formatter
              (Runcode.close_code (gen_cls_wrt f)) in
    print_string "\n----------------------------\n";
    let _ = Print_code.print_closed_code Format.std_formatter
              (Runcode.close_code (gen_cls_wrt f_toplevel)) in
    print_string "\n----------------------------\n";
    ()

MetaOCaml does some very interesting/weird stuff here:

* In printed code it doesn't always show the CSP values, it just says "CSP
  global_ref" for example, but it does that only sometimes. As an example, it
  does that for global_ref, but doesn't do that for f_toplevel. I don't
  understand how are these two any different. I can refer to top level names
  but only sometimes...
  It shows the CSP values in some simple cases, for example if the value is an
  int than it just shows the literal. (not shown in this example)

* I don't know if this is MetaOCaml related, but output of this program is
  interleaved. Instead of printing a line than code it prints two lines and
  then two code etc. How is this possible??

For the reference, the output I'm getting:

  ➜  metaocaml_test git:(master) ✗ ./a.out
  File "metaocaml_test.ml", line 17, characters 19-22:
  Warning 22: The CSP value is a closure or too deep to serialize
  File "metaocaml_test.ml", line 17, characters 19-22:
  Warning 22: The CSP value is a closure or too deep to serialize

  ----------------------------

  ----------------------------
  .<let _ = (* CSP global_ref *) := ((! (* CSP global_ref *)) + 1) in ()>. .<
  let _ = (* CSP global_ref *) := ((! (* CSP global_ref *)) + 1) in ()>.
  ----------------------------
   .<
  match (* CSP i *) with | TestData.Foo i_1 -> (* CSP global_ref *) := i_1>.
  ----------------------------
   .<
  ! (* CSP global_ref *)>.
  ----------------------------
   .<
  ----------------------------
  (* CSP global_ref *) := ((* CSP cls *) ())>. .<
  (* CSP global_ref *) := ((* CSP cls *) ())>.
  ----------------------------


2015-04-30 16:25 GMT-04:00 Ömer Sinan Ağacan <omeragacan@gmail.com>:
> Thanks for the answer.
>
> My main problem is not that some generated code are not printable -- rather,
> it's not clear at all when a code is not printable. Now I have to play around
> with code until suddenly it's printable...
>
> Certainly not all code is printable even in theory, for example, what happens
> if my generated code captures a file handle from code generator? Or a heap
> object that's completely opaque to runtime system.(no type information etc.) In
> those cases it may be possible to directly run the code but it's not possible
> to print it.
>
> But IMHO MetaOCaml should have done a better job at reporting those. Or at
> least at least documenting when it's not possible.
>
> I guess I have to play around and see if some of my random changes make it
> printable.
>
> ---
> Ömer Sinan Ağacan
> http://osa1.net
>
>
> 2015-04-30 15:52 GMT-04:00 Jacques Carette <carette@mcmaster.ca>:
>> You will have some difficulties printing complex closures, especially when
>> they refer to values built in the generator (CSPs) which are not simple
>> values (strings, integers, etc).
>>
>> Sometimes, very simple changes to the generator can allow closures and CSPs
>> to be printable or not -- without very specific examples, I can't help (it's
>> been a few years since I dug into this deeply).
>>
>> I have been able to print rather complex, large codes with metaocaml.  But
>> one has to structure the generator rather carefully to ensure this
>> possibility.
>>
>> Jacques
>>
>>
>> On 2015-04-30 14:36 , Ömer Sinan Ağacan wrote:
>>>
>>> Hi all,
>>>
>>> I'm working on a MetaOCaml program and I want to save generated programs
>>> to
>>> files instead of directly running them within the same program using
>>> `Runcode.(.!)` or `Runcode.run`. The problem is MetaOCaml never prints
>>> generated code, it's always failing with `Warning 22: The CSP value is a
>>> closure or too deep to serialize`.
>>>
>>> I can't see anything related in it's web page:
>>> http://okmij.org/ftp/ML/MetaOCaml.html. What I understand from that page
>>> is
>>> once I have a closed code, I should be able to print it no matter what.
>>> However in my experience even the simplest realistic MetaOCaml program
>>> fails to
>>> generate the code because of this error I mentioned above.
>>>
>>> (One thing to note here is that my program generates the code on a couple
>>> of
>>> inputs, but fails in most of them with this error message.)
>>>
>>> In "Many ways to run the code" section it's said that "Since closed code
>>> is
>>> essentially OCaml AST, after closing the generated code, the user may
>>> examine
>>> and `run' it in many ways. One way of running the code is printing it."
>>> and
>>> then it lists some API functions for printing. In my experience none of
>>> them
>>> really work, I have closed code which I successfully closed using
>>> `Runcode.close_code`, but `print_closed_code` is still failing with the
>>> error,
>>> and `print_code_as_ast` is printing something that definitely doesn't look
>>> like
>>> an AST for any imaginable programming language.(okay... I might have
>>> exaggerated a bit, but it's definitely not OCaml AST and it contains some
>>> references to generator program source, like "Generator.ml[248]" for
>>> example)
>>>
>>> One relevant thing I could find in the documentation is this: "If the code
>>> includes CSP only as literals or external references (and any code can be
>>> arranged that way), the code can be stored into a file and then passed to
>>> ocamlopt." If we remove this sentence from the documentation, I don't
>>> think it
>>> mentions about any possible failures in code printing.
>>>
>>> So now that I've expressed my frustration about this, I guess my main
>>> question
>>> is: In what cases does MetaOCaml prints generated code? In what cases it
>>> doesn't? Note that it fails to generate code even after calling
>>> `print_closed_code (close_code ...)`, so being closed or not doesn't seem
>>> very
>>> relevent here. Is this a bug in MetaOCaml? Are there any workarounds? Any
>>> ideas
>>> what am I doing wrong?
>>>
>>> Thanks in advance for any answers,
>>>
>>> Ömer
>>>
>>

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [Caml-list] Problems with printing MetaOCaml generated code
  2015-04-30 20:57     ` Ömer Sinan Ağacan
@ 2015-04-30 21:35       ` Jeremy Yallop
  2015-05-01 11:21       ` oleg
  1 sibling, 0 replies; 23+ messages in thread
From: Jeremy Yallop @ 2015-04-30 21:35 UTC (permalink / raw)
  To: Ömer Sinan Ağacan; +Cc: OCaml Mailing List

On 30 April 2015 at 21:57, Ömer Sinan Ağacan <omeragacan@gmail.com> wrote:
> Let's talk on an example:
>
> -- contents of TestData.ml
>   type foo = Foo of int
>
> -- contents of main
>   open TestData
>
>   let global_ref : int ref = ref 0
>
>   let gen_inc =
>     .< let _ = global_ref := !global_ref + 1 in () >.

You can improve the output here (and everywhere else that you use
global_ref in a quotation) by putting the global reference in a
separate file, so that MetaOCaml can persist it as a path:

   let gen_inc =
     .< let _ = Globals.global_ref := !Globals.global_ref + 1 in () >.

>   let gen_write i =
>     .< match i with
>        | Foo i -> global_ref := i
>      >.

In this case the problem is that 'i' is a local variable bound to a
current-stage value.  It's better to make it a future-stage (code)
expression, and splice that in:

   let gen_write i =
     .< match .~i with
        | Foo i -> global_ref := i
      >.

You'll also need to change the call:

    gen_write .<Foo 10>.

>   let gen_cls_wrt cls =
>     .< global_ref := cls () >.

This time there are two problems.  First, cls is local, as with 'i'
above.  Second, 'cls' is a closure (function), so it doesn't have a
printed representation.  You can address the problem by making cls
either a code value or a top-level path, e.g.

     .< Globals.global_ref := Globals.cls () >.

or

     .< Globals.global_ref := .~cls () >.

With these changes the program runs without warnings or errors and
generates compilable code without CSP comments.

> * I don't know if this is MetaOCaml related, but output of this program is
>   interleaved. Instead of printing a line than code it prints two lines and
>   then two code etc. How is this possible??

The interleaving is probably due to internal buffering in the format library.

Jeremy.

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [Caml-list] Problems with printing MetaOCaml generated code
  2015-04-30 20:57     ` Ömer Sinan Ağacan
  2015-04-30 21:35       ` Jeremy Yallop
@ 2015-05-01 11:21       ` oleg
  2015-05-01 14:34         ` Ömer Sinan Ağacan
  1 sibling, 1 reply; 23+ messages in thread
From: oleg @ 2015-05-01 11:21 UTC (permalink / raw)
  To: omeragacan; +Cc: yallop, caml-list


After Jeremy's thorough reply, there is little more to say. I'd like
to reinforce a few points. First of all, I was confused by

  > The problem is MetaOCaml never prints generated code, 
  > it's always failing with `Warning 22: The CSP value is a closure or
  > too deep to serialize`.

because Warning 22 is a warning, it is not an error or
failure. Second, MetaOCaml always prints the generated code, with the
proviso that non-seriealizable CSP are printed in a way that make the
code unsuitable for separate compilation. But the code is still
suitable for Runcode.run. (see below). Your concrete example helped.

> So now that I've expressed my frustration about this, I guess my main
> question is: In what cases does MetaOCaml prints generated code? In
> what cases it doesn't? Note that it fails to generate code even after
> calling `print_closed_code (close_code ...)`, so being closed or not
> doesn't seem very relevent here. Is this a bug in MetaOCaml? Are there
> any workarounds? Any ideas what am I doing wrong?

MetaOCaml always prints the generated code. However, if the generated
code contains non-serializable CSP, they are printed in a way that
makes saving the code to a file and then compiling separately
impossible.
Warning 22 was specifically introduced to tell that the generated code
contains a non-serializable CSP. That means that separately compiling
such code is impossible in principle. (I should admit that when CSP is
serializable, it may still be in many cases printed badly -- but at
least that problem is fixable in principle. Or even in practice: CSPs
used internally by MetaOCaml are serializable and are printed in a
good way.)

BTW, one should distinguish ``code with badly printed CSP'' from
``fails to generate code''. The code with badly printed CSP is still a
good code and can be run. So, seeing (* CSP x *) in the output is NOT
a failure of code generation. 

Perhaps a concrete example will help.

# let lift x = .<x>.;;
val lift : 'a -> 'a code = <fun>

# lift "aa";;
- : string code = .<"aa">. 

The generated code can be saved to a file and compiled separately.

# lift 1;;
- : int code = .<(* CSP x *) Obj.magic 1>. 

Here, the generated code looks odd but it is still a well-formed OCaml
code, which may be saved into a file and compiled separately.


# let p = lift (+);;
val p : (int -> int -> int) code = .<(* CSP x *)>. 

This code cannot be compiled separately (and it is accompanied by
Warning 22). Here, CSP is a function (closure). How do you print
closures (other than a sequence of bytes in memory, which is not very
informative)? Saving it to a file is also problematic. 

Yet this is NO failure of code generation. The code p can be used as
any other code value, for example being spliced:

# let p1 = .<.~p 1 2>.;;
val p1 : int code = .<(* CSP x *) 1 2>. 

And we can run the result:

# Runcode.run p1;;
- : int = 3

There is no problems here.

I should stress that there are two ways of using MetaOCaml: run-time
code specialization and generating code for off-line use. In the
former case, it is appropriate, and even beneficial, to share values
between the generator and the generated code, via the common
heap. This is especially good for large values or for closures, open
channels, etc. Such sharing through the common heap is bad for
off-line use, because there is no common heap any more. Warning 22 is
emitted when there is shared through the common heap. This warning is
issued at run-time of the generator: it is difficult to detect
heap-based sharing at compile time: look at the function lift above.
It is polymorphic, so we can't tell if sharing through the heap will
be required from the type of the function (or its definition). In some
uses of this function, like (lift "aa") and (lift 1), no heap sharing
occurs (or, at least, it is not essential and irrelevant). In some
cases, like (lift (+)), the heap-sharing is essential. 

That said, there is something we can do. For example, we can prohibit
polymorphic lifting, like lift above. The user will have to supply
their own function of the type t -> t code for some the concrete type
t. Perhaps that is the way to go, and I am evaluating it. Warning 22
is specifically introduced to help determine how much work the user
will have to do if this solution is implemented. Basically, Warning 22
will become a compile-time error, and the user will have to supply
their own lifting function. That's where modular implicits will be of
great help.


> and `print_code_as_ast` is printing something that definitely doesn't
> look like an AST for any imaginable programming language.(okay... I
> might have exaggerated a bit, but it's definitely not OCaml AST and it
> contains some references to generator program source, like
> "Generator.ml[248]" for example)

It may be hard to accept this, but what you see as the output of
print_code_as_ast is indeed the OCaml AST, printed by OCaml's own
Printast.implementation function.


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [Caml-list] Problems with printing MetaOCaml generated code
  2015-05-01 11:21       ` oleg
@ 2015-05-01 14:34         ` Ömer Sinan Ağacan
  2015-05-01 16:16           ` Leo White
  2015-05-06  9:50           ` oleg
  0 siblings, 2 replies; 23+ messages in thread
From: Ömer Sinan Ağacan @ 2015-05-01 14:34 UTC (permalink / raw)
  To: oleg; +Cc: yallop, OCaml Mailing List

Thanks for all the answers,

> MetaOCaml always prints the generated code. However, if the generated code
> contains non-serializable CSP, they are printed in a way that makes saving
> the code to a file and then compiling separately impossible.

Can we talk about what is non-serializable here? I pushed some code to a
public repo for demonstration purposes. I have a simple interpreter for
a simple language. I'm experimenting with different levels of
interpreter specializations(aka. first Futamura projections). As a
simplest specialization, I want to eliminate parsing costs. The code
that's supposed to do this is here:

https://github.com/osa1/int-proj/blob/master/Unlambda.ml#L204

`p'` in that code is lifted, and it's parsed syntax tree of given source
file. Syntax tree is defined here:

https://github.com/osa1/int-proj/blob/master/Syntax.ml#L63

I think it doesn't have anything that's not serializable: It's just a
simple monomorphic type, doesn't have any closures etc.

But MetaOCaml is failing to print this code. To try it yourself, make
sure you have metaocamlc in $PATH, and run:

  ➜  unlambda git:(master) ✗ make unlambda_metaocaml
  metaocamlc -c Syntax.ml
  metaocamlc Syntax.cmo Unlambda.ml -o unlambda_metaocaml

  ➜  unlambda git:(master) ✗ ./unlambda_metaocaml programs/Hello.unl stage0
  File "Unlambda.ml", line 204, characters 67-69:
  Warning 22: The CSP value is a closure or too deep to serialize
  File "Unlambda.ml", line 204, characters 58-66:
  Warning 22: The CSP value is a closure or too deep to serialize
  .<(* CSP eval_ref *) (* CSP p' *) []>.

To make my point clear: I don't actually need to print the code, even
though offline compilation would be awesome, I'm fine with just (.!)ing
my code for now. But I should be able to see the transformations I'm
doing. I'm perfectly fine with just (.!)ing my code, as long as I can
see what I'm running.

But in this case MetaOCaml is failing to print a code that IMO is
completely printable.

Thanks again for very helpful responses.

2015-05-01 7:21 GMT-04:00  <oleg@okmij.org>:
>
> After Jeremy's thorough reply, there is little more to say. I'd like
> to reinforce a few points. First of all, I was confused by
>
>   > The problem is MetaOCaml never prints generated code,
>   > it's always failing with `Warning 22: The CSP value is a closure or
>   > too deep to serialize`.
>
> because Warning 22 is a warning, it is not an error or
> failure. Second, MetaOCaml always prints the generated code, with the
> proviso that non-seriealizable CSP are printed in a way that make the
> code unsuitable for separate compilation. But the code is still
> suitable for Runcode.run. (see below). Your concrete example helped.
>
>> So now that I've expressed my frustration about this, I guess my main
>> question is: In what cases does MetaOCaml prints generated code? In
>> what cases it doesn't? Note that it fails to generate code even after
>> calling `print_closed_code (close_code ...)`, so being closed or not
>> doesn't seem very relevent here. Is this a bug in MetaOCaml? Are there
>> any workarounds? Any ideas what am I doing wrong?
>
> MetaOCaml always prints the generated code. However, if the generated
> code contains non-serializable CSP, they are printed in a way that
> makes saving the code to a file and then compiling separately
> impossible.
> Warning 22 was specifically introduced to tell that the generated code
> contains a non-serializable CSP. That means that separately compiling
> such code is impossible in principle. (I should admit that when CSP is
> serializable, it may still be in many cases printed badly -- but at
> least that problem is fixable in principle. Or even in practice: CSPs
> used internally by MetaOCaml are serializable and are printed in a
> good way.)
>
> BTW, one should distinguish ``code with badly printed CSP'' from
> ``fails to generate code''. The code with badly printed CSP is still a
> good code and can be run. So, seeing (* CSP x *) in the output is NOT
> a failure of code generation.
>
> Perhaps a concrete example will help.
>
> # let lift x = .<x>.;;
> val lift : 'a -> 'a code = <fun>
>
> # lift "aa";;
> - : string code = .<"aa">.
>
> The generated code can be saved to a file and compiled separately.
>
> # lift 1;;
> - : int code = .<(* CSP x *) Obj.magic 1>.
>
> Here, the generated code looks odd but it is still a well-formed OCaml
> code, which may be saved into a file and compiled separately.
>
>
> # let p = lift (+);;
> val p : (int -> int -> int) code = .<(* CSP x *)>.
>
> This code cannot be compiled separately (and it is accompanied by
> Warning 22). Here, CSP is a function (closure). How do you print
> closures (other than a sequence of bytes in memory, which is not very
> informative)? Saving it to a file is also problematic.
>
> Yet this is NO failure of code generation. The code p can be used as
> any other code value, for example being spliced:
>
> # let p1 = .<.~p 1 2>.;;
> val p1 : int code = .<(* CSP x *) 1 2>.
>
> And we can run the result:
>
> # Runcode.run p1;;
> - : int = 3
>
> There is no problems here.
>
> I should stress that there are two ways of using MetaOCaml: run-time
> code specialization and generating code for off-line use. In the
> former case, it is appropriate, and even beneficial, to share values
> between the generator and the generated code, via the common
> heap. This is especially good for large values or for closures, open
> channels, etc. Such sharing through the common heap is bad for
> off-line use, because there is no common heap any more. Warning 22 is
> emitted when there is shared through the common heap. This warning is
> issued at run-time of the generator: it is difficult to detect
> heap-based sharing at compile time: look at the function lift above.
> It is polymorphic, so we can't tell if sharing through the heap will
> be required from the type of the function (or its definition). In some
> uses of this function, like (lift "aa") and (lift 1), no heap sharing
> occurs (or, at least, it is not essential and irrelevant). In some
> cases, like (lift (+)), the heap-sharing is essential.
>
> That said, there is something we can do. For example, we can prohibit
> polymorphic lifting, like lift above. The user will have to supply
> their own function of the type t -> t code for some the concrete type
> t. Perhaps that is the way to go, and I am evaluating it. Warning 22
> is specifically introduced to help determine how much work the user
> will have to do if this solution is implemented. Basically, Warning 22
> will become a compile-time error, and the user will have to supply
> their own lifting function. That's where modular implicits will be of
> great help.
>
>
>> and `print_code_as_ast` is printing something that definitely doesn't
>> look like an AST for any imaginable programming language.(okay... I
>> might have exaggerated a bit, but it's definitely not OCaml AST and it
>> contains some references to generator program source, like
>> "Generator.ml[248]" for example)
>
> It may be hard to accept this, but what you see as the output of
> print_code_as_ast is indeed the OCaml AST, printed by OCaml's own
> Printast.implementation function.
>

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [Caml-list] Problems with printing MetaOCaml generated code
  2015-05-01 14:34         ` Ömer Sinan Ağacan
@ 2015-05-01 16:16           ` Leo White
  2015-05-01 16:41             ` Ömer Sinan Ağacan
  2015-05-06  9:50           ` oleg
  1 sibling, 1 reply; 23+ messages in thread
From: Leo White @ 2015-05-01 16:16 UTC (permalink / raw)
  To: caml-list

> Can we talk about what is non-serializable here? I pushed some code to a
> public repo for demonstration purposes. I have a simple interpreter for
> a simple language. I'm experimenting with different levels of
> interpreter specializations(aka. first Futamura projections). As a
> simplest specialization, I want to eliminate parsing costs. The code
> that's supposed to do this is here:
> 
> https://github.com/osa1/int-proj/blob/master/Unlambda.ml#L204
> 
> `p'` in that code is lifted, and it's parsed syntax tree of given source
> file. Syntax tree is defined here:
> 
> https://github.com/osa1/int-proj/blob/master/Syntax.ml#L63
> 
> I think it doesn't have anything that's not serializable: It's just a
> simple monomorphic type, doesn't have any closures etc.
> 
> But MetaOCaml is failing to print this code. To try it yourself, make
> sure you have metaocamlc in $PATH, and run:
> 
>   ➜  unlambda git:(master) ✗ make unlambda_metaocaml
>   metaocamlc -c Syntax.ml
>   metaocamlc Syntax.cmo Unlambda.ml -o unlambda_metaocaml
> 
>   ➜  unlambda git:(master) ✗ ./unlambda_metaocaml programs/Hello.unl stage0
>   File "Unlambda.ml", line 204, characters 67-69:
>   Warning 22: The CSP value is a closure or too deep to serialize
>   File "Unlambda.ml", line 204, characters 58-66:
>   Warning 22: The CSP value is a closure or too deep to serialize
>   .<(* CSP eval_ref *) (* CSP p' *) []>.
> 

From a quick look at the code, it seems pretty clear that `eval_ref` is not serializable.
It is a local function so there is no AST fragment which could represent it globally. I
suspect that if you moved `eval_ref` into a separate module, so that it was
a global function, then this code would work.

Regards,

Leo

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [Caml-list] Problems with printing MetaOCaml generated code
  2015-05-01 16:16           ` Leo White
@ 2015-05-01 16:41             ` Ömer Sinan Ağacan
  2015-05-01 16:45               ` Leo White
  0 siblings, 1 reply; 23+ messages in thread
From: Ömer Sinan Ağacan @ 2015-05-01 16:41 UTC (permalink / raw)
  To: Leo White; +Cc: OCaml Mailing List

2015-05-01 12:16 GMT-04:00 Leo White <leo@lpw25.net>:
> From a quick look at the code, it seems pretty clear that `eval_ref` is not serializable.
> It is a local function so there is no AST fragment which could represent it globally. I
> suspect that if you moved `eval_ref` into a separate module, so that it was
> a global function, then this code would work.

It should serialize `p'`, not `eval_ref`, I'd expect serialization of
`eval_ref` to be the identifier `eval_ref`.

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [Caml-list] Problems with printing MetaOCaml generated code
  2015-05-01 16:41             ` Ömer Sinan Ağacan
@ 2015-05-01 16:45               ` Leo White
  2015-05-01 16:53                 ` Ömer Sinan Ağacan
  0 siblings, 1 reply; 23+ messages in thread
From: Leo White @ 2015-05-01 16:45 UTC (permalink / raw)
  To: Ömer Sinan Ağacan; +Cc: OCaml Mailing List



On Fri, 1 May 2015, at 12:41 PM, Ömer Sinan Ağacan wrote:
> 2015-05-01 12:16 GMT-04:00 Leo White <leo@lpw25.net>:
> > From a quick look at the code, it seems pretty clear that `eval_ref` is not serializable.
> > It is a local function so there is no AST fragment which could represent it globally. I
> > suspect that if you moved `eval_ref` into a separate module, so that it was
> > a global function, then this code would work.
> 
> It should serialize `p'`, not `eval_ref`, I'd expect serialization of
> `eval_ref` to be the identifier `eval_ref`.

You can't serialize `eval_ref` as `eval_ref` because that is a local identifier. If you print
out `eval_ref` into some other ml file and compiler it, it is going to give an "Unbound
identifier eval_ref" error.

Regards,

Leo

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [Caml-list] Problems with printing MetaOCaml generated code
  2015-05-01 16:45               ` Leo White
@ 2015-05-01 16:53                 ` Ömer Sinan Ağacan
  2015-05-02 18:45                   ` Ömer Sinan Ağacan
  0 siblings, 1 reply; 23+ messages in thread
From: Ömer Sinan Ağacan @ 2015-05-01 16:53 UTC (permalink / raw)
  To: Leo White; +Cc: OCaml Mailing List

> You can't serialize `eval_ref` as `eval_ref` because that is a local
> identifier. If you print out `eval_ref` into some other ml file and compiler
> it, it is going to give an "Unbound identifier eval_ref" error.

That's true. Just to make sure and make the output more clear, I moved the
relevant code to another module, and now it's printing this:

.<Unlambda.eval_ref (* CSP p' *) []>.

My main question is that it should serialize p' here, but it doesn't. I'm
trying to understand why.

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [Caml-list] Problems with printing MetaOCaml generated code
  2015-05-01 16:53                 ` Ömer Sinan Ağacan
@ 2015-05-02 18:45                   ` Ömer Sinan Ağacan
  2015-05-02 20:49                     ` Jacques Carette
  0 siblings, 1 reply; 23+ messages in thread
From: Ömer Sinan Ağacan @ 2015-05-02 18:45 UTC (permalink / raw)
  To: OCaml Mailing List

In case anyone's still interested, I produced a very simple example that
demonstrates the issue:

  ➜  metaocaml_serialization_issue git:(master) ✗ ls
  Main.ml  Syntax.ml
  ➜  metaocaml_serialization_issue git:(master) ✗ cat Syntax.ml
  type stx =
    | A
    | B of stx
    | C of (stx * stx)
  ➜  metaocaml_serialization_issue git:(master) ✗ cat Main.ml
  open Format
  open Print_code
  open Runcode
  open Syntax

  let _ =
    let stx1 = A in
    let stx2 = B A in
    let stx3 = C (A, A) in

    print_code std_formatter .< stx1 >.;
    print_code std_formatter .< stx2 >.;
    print_code std_formatter .< stx3 >.;

    print_closed_code std_formatter (close_code .< stx1 >.);
    print_closed_code std_formatter (close_code .< stx2 >.);
    print_closed_code std_formatter (close_code .< stx3 >.);
  ➜  metaocaml_serialization_issue git:(master) ✗ metaocamlc Syntax.ml -c
  ➜  metaocaml_serialization_issue git:(master) ✗ metaocamlc
Syntax.cmo Main.ml -o main
  ➜  metaocaml_serialization_issue git:(master) ✗ ./main
  .<(* CSP stx1 *) Obj.magic 0>. .<(* CSP stx2 *)>. .<(* CSP stx3 *)>. .<
  (* CSP stx1 *) Obj.magic 0>. .<(* CSP stx2 *)>. .<(* CSP stx3 *)>.
  ➜  metaocaml_serialization_issue git:(master) ✗


2015-05-01 12:53 GMT-04:00 Ömer Sinan Ağacan <omeragacan@gmail.com>:
>> You can't serialize `eval_ref` as `eval_ref` because that is a local
>> identifier. If you print out `eval_ref` into some other ml file and compiler
>> it, it is going to give an "Unbound identifier eval_ref" error.
>
> That's true. Just to make sure and make the output more clear, I moved the
> relevant code to another module, and now it's printing this:
>
> .<Unlambda.eval_ref (* CSP p' *) []>.
>
> My main question is that it should serialize p' here, but it doesn't. I'm
> trying to understand why.

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [Caml-list] Problems with printing MetaOCaml generated code
  2015-05-02 18:45                   ` Ömer Sinan Ağacan
@ 2015-05-02 20:49                     ` Jacques Carette
  2015-05-03  1:56                       ` Ömer Sinan Ağacan
  0 siblings, 1 reply; 23+ messages in thread
From: Jacques Carette @ 2015-05-02 20:49 UTC (permalink / raw)
  To: Ömer Sinan Ağacan, OCaml Mailing List

try instead
    let stx1 = .< A >. in
and then
    print_code std_formatter .< .~stx1 >. ;

That ought to work as you wish.

Jacques

On 2015-05-02 2:45 PM, Ömer Sinan Ağacan wrote:
> In case anyone's still interested, I produced a very simple example that
> demonstrates the issue:
>
>    ➜  metaocaml_serialization_issue git:(master) ✗ ls
>    Main.ml  Syntax.ml
>    ➜  metaocaml_serialization_issue git:(master) ✗ cat Syntax.ml
>    type stx =
>      | A
>      | B of stx
>      | C of (stx * stx)
>    ➜  metaocaml_serialization_issue git:(master) ✗ cat Main.ml
>    open Format
>    open Print_code
>    open Runcode
>    open Syntax
>
>    let _ =
>      let stx1 = A in
>      let stx2 = B A in
>      let stx3 = C (A, A) in
>
>      print_code std_formatter .< stx1 >.;
>      print_code std_formatter .< stx2 >.;
>      print_code std_formatter .< stx3 >.;
>
>      print_closed_code std_formatter (close_code .< stx1 >.);
>      print_closed_code std_formatter (close_code .< stx2 >.);
>      print_closed_code std_formatter (close_code .< stx3 >.);
>    ➜  metaocaml_serialization_issue git:(master) ✗ metaocamlc Syntax.ml -c
>    ➜  metaocaml_serialization_issue git:(master) ✗ metaocamlc
> Syntax.cmo Main.ml -o main
>    ➜  metaocaml_serialization_issue git:(master) ✗ ./main
>    .<(* CSP stx1 *) Obj.magic 0>. .<(* CSP stx2 *)>. .<(* CSP stx3 *)>. .<
>    (* CSP stx1 *) Obj.magic 0>. .<(* CSP stx2 *)>. .<(* CSP stx3 *)>.
>    ➜  metaocaml_serialization_issue git:(master) ✗
>
>
> 2015-05-01 12:53 GMT-04:00 Ömer Sinan Ağacan <omeragacan@gmail.com>:
>>> You can't serialize `eval_ref` as `eval_ref` because that is a local
>>> identifier. If you print out `eval_ref` into some other ml file and compiler
>>> it, it is going to give an "Unbound identifier eval_ref" error.
>> That's true. Just to make sure and make the output more clear, I moved the
>> relevant code to another module, and now it's printing this:
>>
>> .<Unlambda.eval_ref (* CSP p' *) []>.
>>
>> My main question is that it should serialize p' here, but it doesn't. I'm
>> trying to understand why.


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [Caml-list] Problems with printing MetaOCaml generated code
  2015-05-02 20:49                     ` Jacques Carette
@ 2015-05-03  1:56                       ` Ömer Sinan Ağacan
  2015-05-03  2:28                         ` Jacques Carette
  0 siblings, 1 reply; 23+ messages in thread
From: Ömer Sinan Ağacan @ 2015-05-03  1:56 UTC (permalink / raw)
  To: Jacques Carette; +Cc: OCaml Mailing List

That's not a solution. I should be able to generate some values in
code generation time and persist them in code values, that's the whole
point here.

2015-05-02 16:49 GMT-04:00 Jacques Carette <carette@mcmaster.ca>:
> try instead
>    let stx1 = .< A >. in
> and then
>    print_code std_formatter .< .~stx1 >. ;
>
> That ought to work as you wish.
>
> Jacques
>
>
> On 2015-05-02 2:45 PM, Ömer Sinan Ağacan wrote:
>>
>> In case anyone's still interested, I produced a very simple example that
>> demonstrates the issue:
>>
>>    ➜  metaocaml_serialization_issue git:(master) ✗ ls
>>    Main.ml  Syntax.ml
>>    ➜  metaocaml_serialization_issue git:(master) ✗ cat Syntax.ml
>>    type stx =
>>      | A
>>      | B of stx
>>      | C of (stx * stx)
>>    ➜  metaocaml_serialization_issue git:(master) ✗ cat Main.ml
>>    open Format
>>    open Print_code
>>    open Runcode
>>    open Syntax
>>
>>    let _ =
>>      let stx1 = A in
>>      let stx2 = B A in
>>      let stx3 = C (A, A) in
>>
>>      print_code std_formatter .< stx1 >.;
>>      print_code std_formatter .< stx2 >.;
>>      print_code std_formatter .< stx3 >.;
>>
>>      print_closed_code std_formatter (close_code .< stx1 >.);
>>      print_closed_code std_formatter (close_code .< stx2 >.);
>>      print_closed_code std_formatter (close_code .< stx3 >.);
>>    ➜  metaocaml_serialization_issue git:(master) ✗ metaocamlc Syntax.ml -c
>>    ➜  metaocaml_serialization_issue git:(master) ✗ metaocamlc
>> Syntax.cmo Main.ml -o main
>>    ➜  metaocaml_serialization_issue git:(master) ✗ ./main
>>    .<(* CSP stx1 *) Obj.magic 0>. .<(* CSP stx2 *)>. .<(* CSP stx3 *)>. .<
>>    (* CSP stx1 *) Obj.magic 0>. .<(* CSP stx2 *)>. .<(* CSP stx3 *)>.
>>    ➜  metaocaml_serialization_issue git:(master) ✗
>>
>>
>> 2015-05-01 12:53 GMT-04:00 Ömer Sinan Ağacan <omeragacan@gmail.com>:
>>>>
>>>> You can't serialize `eval_ref` as `eval_ref` because that is a local
>>>> identifier. If you print out `eval_ref` into some other ml file and
>>>> compiler
>>>> it, it is going to give an "Unbound identifier eval_ref" error.
>>>
>>> That's true. Just to make sure and make the output more clear, I moved
>>> the
>>> relevant code to another module, and now it's printing this:
>>>
>>> .<Unlambda.eval_ref (* CSP p' *) []>.
>>>
>>> My main question is that it should serialize p' here, but it doesn't. I'm
>>> trying to understand why.
>
>

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [Caml-list] Problems with printing MetaOCaml generated code
  2015-05-03  1:56                       ` Ömer Sinan Ağacan
@ 2015-05-03  2:28                         ` Jacques Carette
  2015-05-03  3:19                           ` Ömer Sinan Ağacan
  0 siblings, 1 reply; 23+ messages in thread
From: Jacques Carette @ 2015-05-03  2:28 UTC (permalink / raw)
  To: Ömer Sinan Ağacan; +Cc: OCaml Mailing List

But that's the whole point: you are not persisting a value, you are 
persisting a local variable.

In the context of staging, a variable and its value are radically 
different, unlike in the traditional functional programming context, 
where this difference can be safely and harmlessly blurred.

If you want to persist "named values", then give globally accessible 
names to these values [which I believe others have already told you].  
If you want to persist values, then use my solution or a variant of that.

Jacques

On 2015-05-02 9:56 PM, Ömer Sinan Ağacan wrote:
> That's not a solution. I should be able to generate some values in
> code generation time and persist them in code values, that's the whole
> point here.
>
> 2015-05-02 16:49 GMT-04:00 Jacques Carette <carette@mcmaster.ca>:
>> try instead
>>     let stx1 = .< A >. in
>> and then
>>     print_code std_formatter .< .~stx1 >. ;
>>
>> That ought to work as you wish.
>>
>> Jacques
>>
>>
>> On 2015-05-02 2:45 PM, Ömer Sinan Ağacan wrote:
>>> In case anyone's still interested, I produced a very simple example that
>>> demonstrates the issue:
>>>
>>>     ➜  metaocaml_serialization_issue git:(master) ✗ ls
>>>     Main.ml  Syntax.ml
>>>     ➜  metaocaml_serialization_issue git:(master) ✗ cat Syntax.ml
>>>     type stx =
>>>       | A
>>>       | B of stx
>>>       | C of (stx * stx)
>>>     ➜  metaocaml_serialization_issue git:(master) ✗ cat Main.ml
>>>     open Format
>>>     open Print_code
>>>     open Runcode
>>>     open Syntax
>>>
>>>     let _ =
>>>       let stx1 = A in
>>>       let stx2 = B A in
>>>       let stx3 = C (A, A) in
>>>
>>>       print_code std_formatter .< stx1 >.;
>>>       print_code std_formatter .< stx2 >.;
>>>       print_code std_formatter .< stx3 >.;
>>>
>>>       print_closed_code std_formatter (close_code .< stx1 >.);
>>>       print_closed_code std_formatter (close_code .< stx2 >.);
>>>       print_closed_code std_formatter (close_code .< stx3 >.);
>>>     ➜  metaocaml_serialization_issue git:(master) ✗ metaocamlc Syntax.ml -c
>>>     ➜  metaocaml_serialization_issue git:(master) ✗ metaocamlc
>>> Syntax.cmo Main.ml -o main
>>>     ➜  metaocaml_serialization_issue git:(master) ✗ ./main
>>>     .<(* CSP stx1 *) Obj.magic 0>. .<(* CSP stx2 *)>. .<(* CSP stx3 *)>. .<
>>>     (* CSP stx1 *) Obj.magic 0>. .<(* CSP stx2 *)>. .<(* CSP stx3 *)>.
>>>     ➜  metaocaml_serialization_issue git:(master) ✗
>>>
>>>
>>> 2015-05-01 12:53 GMT-04:00 Ömer Sinan Ağacan <omeragacan@gmail.com>:
>>>>> You can't serialize `eval_ref` as `eval_ref` because that is a local
>>>>> identifier. If you print out `eval_ref` into some other ml file and
>>>>> compiler
>>>>> it, it is going to give an "Unbound identifier eval_ref" error.
>>>> That's true. Just to make sure and make the output more clear, I moved
>>>> the
>>>> relevant code to another module, and now it's printing this:
>>>>
>>>> .<Unlambda.eval_ref (* CSP p' *) []>.
>>>>
>>>> My main question is that it should serialize p' here, but it doesn't. I'm
>>>> trying to understand why.
>>


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [Caml-list] Problems with printing MetaOCaml generated code
  2015-05-03  2:28                         ` Jacques Carette
@ 2015-05-03  3:19                           ` Ömer Sinan Ağacan
  2015-05-03  8:40                             ` Gabriel Scherer
  0 siblings, 1 reply; 23+ messages in thread
From: Ömer Sinan Ağacan @ 2015-05-03  3:19 UTC (permalink / raw)
  To: Jacques Carette; +Cc: OCaml Mailing List

> But that's the whole point: you are not persisting a value, you are
> persisting a local variable.

Can you explain what's wrong with that? I'm making sure that the local
variables I'm trying to persist are persistable, as in my last example:

  let stx = A in .< stx >.

(Btw, MetaML has explicit `lift` function for this operation, I'm wondering if
there are any differences between MetaML's `lift` and MetaOCaml's implicit
lifting)

> In the context of staging, a variable and its value are radically different,
> unlike in the traditional functional programming context, where this
> difference can be safely and harmlessly blurred.

I understand that code values are similar to closures in some ways, for example
they capture some variables, and they're not always serializable. My problem
here is that they're almost never serializable in the case of MetaOCaml. It
even fails to serialize a code object that just holds a single constructor for
a simple type with one constructor, for example.

(It'd be really great if you could elaborate on how they're "radically
different")

> If you want to persist "named values", then give globally accessible names to
> these values [which I believe others have already told you].

...

> If you want to persist values, then use my solution or a variant of that.

Can you explain how is this a "solution"? To rephrase my goal one more time: I'm
generating specialized code in runtime, but instead of running it, I want to
serialize it so that I can 1) inspect the generated code and make sure I'm
really doing the optimizations I'm expecting to do 2) I can compile my code
separately. But MetaOCaml is just refusing to show data values in my generated
code.

I started to feel like the story of MetaOCaml serialization as described in
manual's "Many ways to run the code" section is just wrong.

2015-05-02 22:28 GMT-04:00 Jacques Carette <carette@mcmaster.ca>:
> But that's the whole point: you are not persisting a value, you are
> persisting a local variable.
>
> In the context of staging, a variable and its value are radically different,
> unlike in the traditional functional programming context, where this
> difference can be safely and harmlessly blurred.
>
> If you want to persist "named values", then give globally accessible names
> to these values [which I believe others have already told you].  If you want
> to persist values, then use my solution or a variant of that.
>
> Jacques
>
>
> On 2015-05-02 9:56 PM, Ömer Sinan Ağacan wrote:
>>
>> That's not a solution. I should be able to generate some values in
>> code generation time and persist them in code values, that's the whole
>> point here.
>>
>> 2015-05-02 16:49 GMT-04:00 Jacques Carette <carette@mcmaster.ca>:
>>>
>>> try instead
>>>     let stx1 = .< A >. in
>>> and then
>>>     print_code std_formatter .< .~stx1 >. ;
>>>
>>> That ought to work as you wish.
>>>
>>> Jacques
>>>
>>>
>>> On 2015-05-02 2:45 PM, Ömer Sinan Ağacan wrote:
>>>>
>>>> In case anyone's still interested, I produced a very simple example that
>>>> demonstrates the issue:
>>>>
>>>>     ➜  metaocaml_serialization_issue git:(master) ✗ ls
>>>>     Main.ml  Syntax.ml
>>>>     ➜  metaocaml_serialization_issue git:(master) ✗ cat Syntax.ml
>>>>     type stx =
>>>>       | A
>>>>       | B of stx
>>>>       | C of (stx * stx)
>>>>     ➜  metaocaml_serialization_issue git:(master) ✗ cat Main.ml
>>>>     open Format
>>>>     open Print_code
>>>>     open Runcode
>>>>     open Syntax
>>>>
>>>>     let _ =
>>>>       let stx1 = A in
>>>>       let stx2 = B A in
>>>>       let stx3 = C (A, A) in
>>>>
>>>>       print_code std_formatter .< stx1 >.;
>>>>       print_code std_formatter .< stx2 >.;
>>>>       print_code std_formatter .< stx3 >.;
>>>>
>>>>       print_closed_code std_formatter (close_code .< stx1 >.);
>>>>       print_closed_code std_formatter (close_code .< stx2 >.);
>>>>       print_closed_code std_formatter (close_code .< stx3 >.);
>>>>     ➜  metaocaml_serialization_issue git:(master) ✗ metaocamlc Syntax.ml
>>>> -c
>>>>     ➜  metaocaml_serialization_issue git:(master) ✗ metaocamlc
>>>> Syntax.cmo Main.ml -o main
>>>>     ➜  metaocaml_serialization_issue git:(master) ✗ ./main
>>>>     .<(* CSP stx1 *) Obj.magic 0>. .<(* CSP stx2 *)>. .<(* CSP stx3 *)>.
>>>> .<
>>>>     (* CSP stx1 *) Obj.magic 0>. .<(* CSP stx2 *)>. .<(* CSP stx3 *)>.
>>>>     ➜  metaocaml_serialization_issue git:(master) ✗
>>>>
>>>>
>>>> 2015-05-01 12:53 GMT-04:00 Ömer Sinan Ağacan <omeragacan@gmail.com>:
>>>>>>
>>>>>> You can't serialize `eval_ref` as `eval_ref` because that is a local
>>>>>> identifier. If you print out `eval_ref` into some other ml file and
>>>>>> compiler
>>>>>> it, it is going to give an "Unbound identifier eval_ref" error.
>>>>>
>>>>> That's true. Just to make sure and make the output more clear, I moved
>>>>> the
>>>>> relevant code to another module, and now it's printing this:
>>>>>
>>>>> .<Unlambda.eval_ref (* CSP p' *) []>.
>>>>>
>>>>> My main question is that it should serialize p' here, but it doesn't.
>>>>> I'm
>>>>> trying to understand why.
>>>
>>>
>

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [Caml-list] Problems with printing MetaOCaml generated code
  2015-05-03  3:19                           ` Ömer Sinan Ağacan
@ 2015-05-03  8:40                             ` Gabriel Scherer
  2015-05-03 14:28                               ` Ömer Sinan Ağacan
  0 siblings, 1 reply; 23+ messages in thread
From: Gabriel Scherer @ 2015-05-03  8:40 UTC (permalink / raw)
  To: Ömer Sinan Ağacan; +Cc: Jacques Carette, OCaml Mailing List

[-- Attachment #1: Type: text/plain, Size: 7369 bytes --]

.< x >. represents a piece of code that is just the variable x. Printed to
a string, it is "x". (Regardless of the definition of x, for example (A))

.< ~x >. represents a piece of code that is contained in the value of the
variable x. For example, if the value of x is .< A >. , then the string
representation of .< ~x >. would be "A".

When running code in the same MetaOCaml program, you can use them in
closely related ways: running .< f ~x >. will run the function f with the
value of x, A, but running .< f x >. will also work because x acts here as
a reference to a previous stage, and the value of the previous stage
(because it is "serializable") can be transported to the current stage.
(One can think of this as a runtime reference to a compile-time value or
computation)

When printing the code, they are fundamentally different, because indeed
the variable .< x >. may not mean anything in printed code if it is only
meaningful in the local context. Consider:

  print_code (let x = A in .< x >.)

what could the program print here? "x" would be wrong, because the receiver
of the code has no way to know what "x" means (the declaration of x is at
the previous stage, it is not printed).

On the contrary, with:

  lib.ml:
    let x = A

  main.ml:
    print_code (let open Lib in .< x >.)

there, because x is a reference that *can be named* at the toplevel of an
OCaml program, you can print something, namely "Lib.x".

On Sun, May 3, 2015 at 5:19 AM, Ömer Sinan Ağacan <omeragacan@gmail.com>
wrote:

> > But that's the whole point: you are not persisting a value, you are
> > persisting a local variable.
>
> Can you explain what's wrong with that? I'm making sure that the local
> variables I'm trying to persist are persistable, as in my last example:
>
>   let stx = A in .< stx >.
>
> (Btw, MetaML has explicit `lift` function for this operation, I'm
> wondering if
> there are any differences between MetaML's `lift` and MetaOCaml's implicit
> lifting)
>
> > In the context of staging, a variable and its value are radically
> different,
> > unlike in the traditional functional programming context, where this
> > difference can be safely and harmlessly blurred.
>
> I understand that code values are similar to closures in some ways, for
> example
> they capture some variables, and they're not always serializable. My
> problem
> here is that they're almost never serializable in the case of MetaOCaml. It
> even fails to serialize a code object that just holds a single constructor
> for
> a simple type with one constructor, for example.
>
> (It'd be really great if you could elaborate on how they're "radically
> different")
>
> > If you want to persist "named values", then give globally accessible
> names to
> > these values [which I believe others have already told you].
>
> ...
>
> > If you want to persist values, then use my solution or a variant of that.
>
> Can you explain how is this a "solution"? To rephrase my goal one more
> time: I'm
> generating specialized code in runtime, but instead of running it, I want
> to
> serialize it so that I can 1) inspect the generated code and make sure I'm
> really doing the optimizations I'm expecting to do 2) I can compile my code
> separately. But MetaOCaml is just refusing to show data values in my
> generated
> code.
>
> I started to feel like the story of MetaOCaml serialization as described in
> manual's "Many ways to run the code" section is just wrong.
>
> 2015-05-02 22:28 GMT-04:00 Jacques Carette <carette@mcmaster.ca>:
> > But that's the whole point: you are not persisting a value, you are
> > persisting a local variable.
> >
> > In the context of staging, a variable and its value are radically
> different,
> > unlike in the traditional functional programming context, where this
> > difference can be safely and harmlessly blurred.
> >
> > If you want to persist "named values", then give globally accessible
> names
> > to these values [which I believe others have already told you].  If you
> want
> > to persist values, then use my solution or a variant of that.
> >
> > Jacques
> >
> >
> > On 2015-05-02 9:56 PM, Ömer Sinan Ağacan wrote:
> >>
> >> That's not a solution. I should be able to generate some values in
> >> code generation time and persist them in code values, that's the whole
> >> point here.
> >>
> >> 2015-05-02 16:49 GMT-04:00 Jacques Carette <carette@mcmaster.ca>:
> >>>
> >>> try instead
> >>>     let stx1 = .< A >. in
> >>> and then
> >>>     print_code std_formatter .< .~stx1 >. ;
> >>>
> >>> That ought to work as you wish.
> >>>
> >>> Jacques
> >>>
> >>>
> >>> On 2015-05-02 2:45 PM, Ömer Sinan Ağacan wrote:
> >>>>
> >>>> In case anyone's still interested, I produced a very simple example
> that
> >>>> demonstrates the issue:
> >>>>
> >>>>     ➜  metaocaml_serialization_issue git:(master) ✗ ls
> >>>>     Main.ml  Syntax.ml
> >>>>     ➜  metaocaml_serialization_issue git:(master) ✗ cat Syntax.ml
> >>>>     type stx =
> >>>>       | A
> >>>>       | B of stx
> >>>>       | C of (stx * stx)
> >>>>     ➜  metaocaml_serialization_issue git:(master) ✗ cat Main.ml
> >>>>     open Format
> >>>>     open Print_code
> >>>>     open Runcode
> >>>>     open Syntax
> >>>>
> >>>>     let _ =
> >>>>       let stx1 = A in
> >>>>       let stx2 = B A in
> >>>>       let stx3 = C (A, A) in
> >>>>
> >>>>       print_code std_formatter .< stx1 >.;
> >>>>       print_code std_formatter .< stx2 >.;
> >>>>       print_code std_formatter .< stx3 >.;
> >>>>
> >>>>       print_closed_code std_formatter (close_code .< stx1 >.);
> >>>>       print_closed_code std_formatter (close_code .< stx2 >.);
> >>>>       print_closed_code std_formatter (close_code .< stx3 >.);
> >>>>     ➜  metaocaml_serialization_issue git:(master) ✗ metaocamlc
> Syntax.ml
> >>>> -c
> >>>>     ➜  metaocaml_serialization_issue git:(master) ✗ metaocamlc
> >>>> Syntax.cmo Main.ml -o main
> >>>>     ➜  metaocaml_serialization_issue git:(master) ✗ ./main
> >>>>     .<(* CSP stx1 *) Obj.magic 0>. .<(* CSP stx2 *)>. .<(* CSP stx3
> *)>.
> >>>> .<
> >>>>     (* CSP stx1 *) Obj.magic 0>. .<(* CSP stx2 *)>. .<(* CSP stx3 *)>.
> >>>>     ➜  metaocaml_serialization_issue git:(master) ✗
> >>>>
> >>>>
> >>>> 2015-05-01 12:53 GMT-04:00 Ömer Sinan Ağacan <omeragacan@gmail.com>:
> >>>>>>
> >>>>>> You can't serialize `eval_ref` as `eval_ref` because that is a local
> >>>>>> identifier. If you print out `eval_ref` into some other ml file and
> >>>>>> compiler
> >>>>>> it, it is going to give an "Unbound identifier eval_ref" error.
> >>>>>
> >>>>> That's true. Just to make sure and make the output more clear, I
> moved
> >>>>> the
> >>>>> relevant code to another module, and now it's printing this:
> >>>>>
> >>>>> .<Unlambda.eval_ref (* CSP p' *) []>.
> >>>>>
> >>>>> My main question is that it should serialize p' here, but it doesn't.
> >>>>> I'm
> >>>>> trying to understand why.
> >>>
> >>>
> >
>
> --
> Caml-list mailing list.  Subscription management and archives:
> https://sympa.inria.fr/sympa/arc/caml-list
> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
> Bug reports: http://caml.inria.fr/bin/caml-bugs
>

[-- Attachment #2: Type: text/html, Size: 10063 bytes --]

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [Caml-list] Problems with printing MetaOCaml generated code
  2015-05-03  8:40                             ` Gabriel Scherer
@ 2015-05-03 14:28                               ` Ömer Sinan Ağacan
  2015-05-03 15:24                                 ` Leo White
  0 siblings, 1 reply; 23+ messages in thread
From: Ömer Sinan Ağacan @ 2015-05-03 14:28 UTC (permalink / raw)
  To: Gabriel Scherer; +Cc: Jacques Carette, OCaml Mailing List

> .< x >. represents a piece of code that is just the variable x. Printed to a
> string, it is "x". (Regardless of the definition of x, for example (A))

I don't think this is true, as far as I can see MetaOCaml doesn't have open code
values that are only runnable in environments that bind free variables in the
code.

  # .<a>.;;
  Error: Unbound value a
  # let a = 1 in .<a>.;;
  - : int code = .<1>.

In this example `.<a>.` didn't mean a code that is just the variable `a`,
instead, `a` is lifted in code and code is now `.<1>.`.

I think this automatic lifting is why MetaOCaml doesn't have explicit "lift"
operation like MetaML does: variables bound in the environment automatically
lifted, so no open code values are possible.

> When printing the code, they are fundamentally different, because indeed the
> variable .< x >. may not mean anything in printed code if it is only
> meaningful in the local context. Consider:
>
>   print_code (let x = A in .< x >.)
>
> what could the program print here? "x" would be wrong, because the receiver
> of the code has no way to know what "x" means (the declaration of x is at
> the previous stage, it is not printed).

That's exactly what I'm trying to ask here... People are trying to explain that
this should be printed as "A":

  print_code (let x = .< A >. in .< .~ x >.);

But this shouldn't:

  print_code (let x = A in .< x >.);

This doesn't make sense at all. In your example you just said that "x would be
wrong, because receiver of the code has no way to know what x means". Here the
code works like a closure, it captures `x`, but when it comes to printing, it
just prints `CSP value x` instead of printing the value of it, which is
completely serializable, indeed it serializes it in the first case.

Also, note that if the code is only printed in the first case, then it's
impossible to print anything. Because at some point I have to lift some values
in my code values, but then I'm losing the ability to print anyway. Example:

  let stx = B A in
  let c   = .< stc >. in
  print_code .< .~ c >.;;

Prints .< (* CSP stx *) >. . So once you lift something to code values, you lose
the ability to print.

2015-05-03 4:40 GMT-04:00 Gabriel Scherer <gabriel.scherer@gmail.com>:
> .< x >. represents a piece of code that is just the variable x. Printed to a
> string, it is "x". (Regardless of the definition of x, for example (A))
>
> .< ~x >. represents a piece of code that is contained in the value of the
> variable x. For example, if the value of x is .< A >. , then the string
> representation of .< ~x >. would be "A".
>
> When running code in the same MetaOCaml program, you can use them in closely
> related ways: running .< f ~x >. will run the function f with the value of
> x, A, but running .< f x >. will also work because x acts here as a
> reference to a previous stage, and the value of the previous stage (because
> it is "serializable") can be transported to the current stage. (One can
> think of this as a runtime reference to a compile-time value or computation)
>
> When printing the code, they are fundamentally different, because indeed the
> variable .< x >. may not mean anything in printed code if it is only
> meaningful in the local context. Consider:
>
>   print_code (let x = A in .< x >.)
>
> what could the program print here? "x" would be wrong, because the receiver
> of the code has no way to know what "x" means (the declaration of x is at
> the previous stage, it is not printed).
>
> On the contrary, with:
>
>   lib.ml:
>     let x = A
>
>   main.ml:
>     print_code (let open Lib in .< x >.)
>
> there, because x is a reference that *can be named* at the toplevel of an
> OCaml program, you can print something, namely "Lib.x".
>
> On Sun, May 3, 2015 at 5:19 AM, Ömer Sinan Ağacan <omeragacan@gmail.com>
> wrote:
>>
>> > But that's the whole point: you are not persisting a value, you are
>> > persisting a local variable.
>>
>> Can you explain what's wrong with that? I'm making sure that the local
>> variables I'm trying to persist are persistable, as in my last example:
>>
>>   let stx = A in .< stx >.
>>
>> (Btw, MetaML has explicit `lift` function for this operation, I'm
>> wondering if
>> there are any differences between MetaML's `lift` and MetaOCaml's implicit
>> lifting)
>>
>> > In the context of staging, a variable and its value are radically
>> > different,
>> > unlike in the traditional functional programming context, where this
>> > difference can be safely and harmlessly blurred.
>>
>> I understand that code values are similar to closures in some ways, for
>> example
>> they capture some variables, and they're not always serializable. My
>> problem
>> here is that they're almost never serializable in the case of MetaOCaml.
>> It
>> even fails to serialize a code object that just holds a single constructor
>> for
>> a simple type with one constructor, for example.
>>
>> (It'd be really great if you could elaborate on how they're "radically
>> different")
>>
>> > If you want to persist "named values", then give globally accessible
>> > names to
>> > these values [which I believe others have already told you].
>>
>> ...
>>
>> > If you want to persist values, then use my solution or a variant of
>> > that.
>>
>> Can you explain how is this a "solution"? To rephrase my goal one more
>> time: I'm
>> generating specialized code in runtime, but instead of running it, I want
>> to
>> serialize it so that I can 1) inspect the generated code and make sure I'm
>> really doing the optimizations I'm expecting to do 2) I can compile my
>> code
>> separately. But MetaOCaml is just refusing to show data values in my
>> generated
>> code.
>>
>> I started to feel like the story of MetaOCaml serialization as described
>> in
>> manual's "Many ways to run the code" section is just wrong.
>>
>> 2015-05-02 22:28 GMT-04:00 Jacques Carette <carette@mcmaster.ca>:
>> > But that's the whole point: you are not persisting a value, you are
>> > persisting a local variable.
>> >
>> > In the context of staging, a variable and its value are radically
>> > different,
>> > unlike in the traditional functional programming context, where this
>> > difference can be safely and harmlessly blurred.
>> >
>> > If you want to persist "named values", then give globally accessible
>> > names
>> > to these values [which I believe others have already told you].  If you
>> > want
>> > to persist values, then use my solution or a variant of that.
>> >
>> > Jacques
>> >
>> >
>> > On 2015-05-02 9:56 PM, Ömer Sinan Ağacan wrote:
>> >>
>> >> That's not a solution. I should be able to generate some values in
>> >> code generation time and persist them in code values, that's the whole
>> >> point here.
>> >>
>> >> 2015-05-02 16:49 GMT-04:00 Jacques Carette <carette@mcmaster.ca>:
>> >>>
>> >>> try instead
>> >>>     let stx1 = .< A >. in
>> >>> and then
>> >>>     print_code std_formatter .< .~stx1 >. ;
>> >>>
>> >>> That ought to work as you wish.
>> >>>
>> >>> Jacques
>> >>>
>> >>>
>> >>> On 2015-05-02 2:45 PM, Ömer Sinan Ağacan wrote:
>> >>>>
>> >>>> In case anyone's still interested, I produced a very simple example
>> >>>> that
>> >>>> demonstrates the issue:
>> >>>>
>> >>>>     ➜  metaocaml_serialization_issue git:(master) ✗ ls
>> >>>>     Main.ml  Syntax.ml
>> >>>>     ➜  metaocaml_serialization_issue git:(master) ✗ cat Syntax.ml
>> >>>>     type stx =
>> >>>>       | A
>> >>>>       | B of stx
>> >>>>       | C of (stx * stx)
>> >>>>     ➜  metaocaml_serialization_issue git:(master) ✗ cat Main.ml
>> >>>>     open Format
>> >>>>     open Print_code
>> >>>>     open Runcode
>> >>>>     open Syntax
>> >>>>
>> >>>>     let _ =
>> >>>>       let stx1 = A in
>> >>>>       let stx2 = B A in
>> >>>>       let stx3 = C (A, A) in
>> >>>>
>> >>>>       print_code std_formatter .< stx1 >.;
>> >>>>       print_code std_formatter .< stx2 >.;
>> >>>>       print_code std_formatter .< stx3 >.;
>> >>>>
>> >>>>       print_closed_code std_formatter (close_code .< stx1 >.);
>> >>>>       print_closed_code std_formatter (close_code .< stx2 >.);
>> >>>>       print_closed_code std_formatter (close_code .< stx3 >.);
>> >>>>     ➜  metaocaml_serialization_issue git:(master) ✗ metaocamlc
>> >>>> Syntax.ml
>> >>>> -c
>> >>>>     ➜  metaocaml_serialization_issue git:(master) ✗ metaocamlc
>> >>>> Syntax.cmo Main.ml -o main
>> >>>>     ➜  metaocaml_serialization_issue git:(master) ✗ ./main
>> >>>>     .<(* CSP stx1 *) Obj.magic 0>. .<(* CSP stx2 *)>. .<(* CSP stx3
>> >>>> *)>.
>> >>>> .<
>> >>>>     (* CSP stx1 *) Obj.magic 0>. .<(* CSP stx2 *)>. .<(* CSP stx3
>> >>>> *)>.
>> >>>>     ➜  metaocaml_serialization_issue git:(master) ✗
>> >>>>
>> >>>>
>> >>>> 2015-05-01 12:53 GMT-04:00 Ömer Sinan Ağacan <omeragacan@gmail.com>:
>> >>>>>>
>> >>>>>> You can't serialize `eval_ref` as `eval_ref` because that is a
>> >>>>>> local
>> >>>>>> identifier. If you print out `eval_ref` into some other ml file and
>> >>>>>> compiler
>> >>>>>> it, it is going to give an "Unbound identifier eval_ref" error.
>> >>>>>
>> >>>>> That's true. Just to make sure and make the output more clear, I
>> >>>>> moved
>> >>>>> the
>> >>>>> relevant code to another module, and now it's printing this:
>> >>>>>
>> >>>>> .<Unlambda.eval_ref (* CSP p' *) []>.
>> >>>>>
>> >>>>> My main question is that it should serialize p' here, but it
>> >>>>> doesn't.
>> >>>>> I'm
>> >>>>> trying to understand why.
>> >>>
>> >>>
>> >
>>
>> --
>> Caml-list mailing list.  Subscription management and archives:
>> https://sympa.inria.fr/sympa/arc/caml-list
>> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
>> Bug reports: http://caml.inria.fr/bin/caml-bugs
>
>

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [Caml-list] Problems with printing MetaOCaml generated code
  2015-05-03 14:28                               ` Ömer Sinan Ağacan
@ 2015-05-03 15:24                                 ` Leo White
  2015-05-03 15:50                                   ` Ömer Sinan Ağacan
  0 siblings, 1 reply; 23+ messages in thread
From: Leo White @ 2015-05-03 15:24 UTC (permalink / raw)
  To: caml-list

> I don't think this is true, as far as I can see MetaOCaml doesn't have open code
> values that are only runnable in environments that bind free variables in the
> code.
> 
>   # .<a>.;;
>   Error: Unbound value a
>   # let a = 1 in .<a>.;;
>   - : int code = .<1>.
> 
> In this example `.<a>.` didn't mean a code that is just the variable `a`,
> instead, `a` is lifted in code and code is now `.<1>.`.
> 
> I think this automatic lifting is why MetaOCaml doesn't have explicit "lift"
> operation like MetaML does: variables bound in the environment automatically
> lifted, so no open code values are possible.

It is true that MetaOCaml tries to auto-magically lift *some* things for you
(e.g. ints), as in this example. If type information is available, then for known
types it can produce a call to a function such as `Trx.lift_constant_int` to do the
lifting. For other types it will examine the value at run-time and attempt to lift it.
For example, if the value has a "string tag" then it can be represented by a string
literal. If this fails then it will fall back to using true CSP -- which can be run but
cannot be printed.

Personally, I think it is best to avoid this auto-magic and just do your lifting by
hand. The type-based auto-magic doesn't work with polymorphism, whilst the
value-based auto-magic is not parametric.

Regards,

Leo

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [Caml-list] Problems with printing MetaOCaml generated code
  2015-05-03 15:24                                 ` Leo White
@ 2015-05-03 15:50                                   ` Ömer Sinan Ağacan
  0 siblings, 0 replies; 23+ messages in thread
From: Ömer Sinan Ağacan @ 2015-05-03 15:50 UTC (permalink / raw)
  To: Leo White; +Cc: OCaml Mailing List

> Personally, I think it is best to avoid this auto-magic and just do your
> lifting by hand. The type-based auto-magic doesn't work with polymorphism,
> whilst the value-based auto-magic is not parametric.

Hm, I didn't know this was possible. I just tried and it seems to work really
well:

  type stx =
    | A
    | B of stx
    | C of (stx * stx)

  let rec lift_stx (stx : stx) : stx code =
    match stx with
    | A              -> .< A >.
    | B stx'         -> .< B .~ (lift_stx stx') >.
    | C (stx1, stx2) -> .< C ( .~ (lift_stx stx1), .~ (lift_stx stx2) ) >.

  let stx = C (C (C (A, A), C (A, A)), C (C (A, A), C (A, A))) in
  print_code std_formatter .< .~ (lift_stx stx) >.;

So it seems like I finally have a workaround now, thanks!

The story of MetaOCaml code printing is still not completely clear to me, and
this workaround means lots of boilerplace, but at least I have a workaround now
and I can make progress.

2015-05-03 11:24 GMT-04:00 Leo White <leo@lpw25.net>:
>> I don't think this is true, as far as I can see MetaOCaml doesn't have open code
>> values that are only runnable in environments that bind free variables in the
>> code.
>>
>>   # .<a>.;;
>>   Error: Unbound value a
>>   # let a = 1 in .<a>.;;
>>   - : int code = .<1>.
>>
>> In this example `.<a>.` didn't mean a code that is just the variable `a`,
>> instead, `a` is lifted in code and code is now `.<1>.`.
>>
>> I think this automatic lifting is why MetaOCaml doesn't have explicit "lift"
>> operation like MetaML does: variables bound in the environment automatically
>> lifted, so no open code values are possible.
>
> It is true that MetaOCaml tries to auto-magically lift *some* things for you
> (e.g. ints), as in this example. If type information is available, then for known
> types it can produce a call to a function such as `Trx.lift_constant_int` to do the
> lifting. For other types it will examine the value at run-time and attempt to lift it.
> For example, if the value has a "string tag" then it can be represented by a string
> literal. If this fails then it will fall back to using true CSP -- which can be run but
> cannot be printed.
>
> Personally, I think it is best to avoid this auto-magic and just do your lifting by
> hand. The type-based auto-magic doesn't work with polymorphism, whilst the
> value-based auto-magic is not parametric.
>
> Regards,
>
> Leo
>
> --
> Caml-list mailing list.  Subscription management and archives:
> https://sympa.inria.fr/sympa/arc/caml-list
> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
> Bug reports: http://caml.inria.fr/bin/caml-bugs

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [Caml-list] Problems with printing MetaOCaml generated code
  2015-05-01 14:34         ` Ömer Sinan Ağacan
  2015-05-01 16:16           ` Leo White
@ 2015-05-06  9:50           ` oleg
  2015-05-06 15:58             ` Jeremy Yallop
  1 sibling, 1 reply; 23+ messages in thread
From: oleg @ 2015-05-06  9:50 UTC (permalink / raw)
  To: omeragacan; +Cc: caml-list


Leo has given an excellent explanation. I merely wish to stress two
subtle points, which are worth repeating.

If we restrict ourselves to two stages for the sake of explanation, a
cross-stage persistent identifier is the one that is bound outside the
brackets but used within. What will appear in the generated code
depends on whether that identifier is ``global'' or not.  If it is
global, the name of that identifier will appear. If it is local,
MetaOCaml will try to lift the corresponding value one way or
another.

I should stress the special meaning of the ``global identifier''. In
the discussions about CSP, a global identifier is a top-level
identifier *in a different compilation unit*. Emphatically, the
top-level identifier in the current compilation unit is *not*
considered a global identifier.  Therefore, if you write

let foo = fun x -> x
.<foo 1>.
you will see the CSP 
- : int code = .<(* CSP foo *) 1>. 

rather than the expected .<foo 1>..

The reason top-level identifiers in the current module are not
considered global is because they may be re-defined -- even at a
different type. For example, the above program may continue with
        let foo = true
If the generated code were .<foo 1>., which particular foo it would
refer to? BTW, the global references generated by OCaml proper (which
one may refer too) do not have disambiguating timestamps. If you
examine the object file generated by OCaml, you will see just 'foo'.

MetaOCaml-specific processing is done definition-by-definition. When
MetaOCaml typechecker sees 'foo', it has no knowledge if that identifier
will be later redefined.


Suppose the identifier x is not global, and and it appears within
brackets, for example

        .<fun u ->  x>.
You can read this expression as if it were

        .<fun u -> .~(lift_it x)>.

where 'lift_it' is one of the lifting function that MetaOCaml chooses
for you. For example, if x is of the type int, then lift_it is essentially
string_of_int. If x is not one of the few types MetaOCaml knows a
priori how to lift (or if x is polymorphic and so its exact type
cannot be determined), then lift_it is chosen to be a dynquote, a
function that examines the run-time representation of the value and
tries to do something intelligent. Since the type information is
erased by that time (or was not available to start with, if x was
polymorphic), we cannot distinguish the integer 0 from None from []
or from the first 0-ary constructor of any data type. All of them are
represented internally as 0. That's why you see Obj.magic 0 in the
generated code.

Of course MetaOCaml serialization can be improved. What I'd like to
stress is that you don't have to wait for the improvement. You can
always, instead of
        .<fun u ->  x>.
write
        .<fun u -> .~(mylift x)>.
where
        mylift : t -> t code
is *your* function that does whatever _you_ like it to do at that
particular type t (it should still produce something of the type (t
code)).

If some particular mylift functions turn out popular, they can be
added to MetaOCaml, to save everyone trouble writing them.

And I generally agree with Leo that this implicit lifting is
baroque. At present I'm not sure if requiring the explicit lifting is
too much of a burden. I'm sure that with modular implicits, it won't
be.


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [Caml-list] Problems with printing MetaOCaml generated code
  2015-05-06  9:50           ` oleg
@ 2015-05-06 15:58             ` Jeremy Yallop
  2015-05-06 16:45               ` Yotam Barnoy
  0 siblings, 1 reply; 23+ messages in thread
From: Jeremy Yallop @ 2015-05-06 15:58 UTC (permalink / raw)
  To: Oleg Kiselyov; +Cc: Ömer Sinan Ağacan, Caml List

On 6 May 2015 at 10:50,  <oleg@okmij.org> wrote:
> Of course MetaOCaml serialization can be improved. What I'd like to
> stress is that you don't have to wait for the improvement. You can
> always, instead of
>         .<fun u ->  x>.
> write
>         .<fun u -> .~(mylift x)>.
> where
>         mylift : t -> t code
> is *your* function that does whatever _you_ like it to do at that
> particular type t (it should still produce something of the type (t
> code)).
>
> If some particular mylift functions turn out popular, they can be
> added to MetaOCaml, to save everyone trouble writing them.
>
> And I generally agree with Leo that this implicit lifting is
> baroque. At present I'm not sure if requiring the explicit lifting is
> too much of a burden. I'm sure that with modular implicits, it won't
> be.

I've just pushed an OPAM switch for an OCaml compiler that combines
the MetaOCaml and modular implicits patches, making it possible to
experiment with explicit user-defined polymorphic CSP.

For example, you might define a signature, CSP, for "things that can
be persisted":

  module type CSP =
   sig
     type t
     val lift : t -> t code
  end

together with a top-level function that dispatches to the appropriate instance

  let csp (implicit C: CSP) (x : C.t) = C.lift x

and instances of CSP for each type of interest.  Here's an instance
for the stx type from earlier in the thread:

  implicit module CSP_stx : CSP with type t = stx =
  struct
    type t = stx

    let rec lift : stx -> stx code = function
      | A -> .< A >.
      | B s -> .< B .~ (lift s) >.
      | C (s1, s2) -> .< C ( .~(lift s1), .~(lift s2) ) >.
   end

and here's a parameterised instance for lists that makes it possible
to persist lists of any persistable element type:

  implicit functor CSP_list(C: CSP) : CSP with type t = C.t list =
  struct
    type t = C.t list

    let rec lift : C.t list -> C.t list code = function
        [] -> .< [] >.
      | x :: xs -> .< .~(csp x) :: .~(lift xs) >.
  end

These two instances make it possible to use the CSP function to
persist stx values, or lists of stx values, or lists of lists of stx
values (etc.):

   # let ba = B A in .< .~(csp ba) >.;;
   - : stx code = .<Stx.B Stx.A>.

  # let l = [A; B A] in .< .~(csp l) >.;;
  - : stx list code = .<[Stx.A; Stx.B Stx.A]>.

  # let ll = [[A; B A]] and ba = B A in .< .~(csp ll), .~(csp ba) >.;;
  - : (stx list list * stx) code = .<([[Stx.A; Stx.B Stx.A]], (Stx.B Stx.A))>.

It's easy to imagine having the csp function built in to MetaOCaml, so
that we could write .< x >.  (or some similarly convenient syntax) to
mean .< .~(csp x) >...

You can try out the switch with OPAM in the usual way:

   opam update
   opam switch 4.02.1+modular-implicits-ber
   eval `opam config env`

Jeremy.

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [Caml-list] Problems with printing MetaOCaml generated code
  2015-05-06 15:58             ` Jeremy Yallop
@ 2015-05-06 16:45               ` Yotam Barnoy
  0 siblings, 0 replies; 23+ messages in thread
From: Yotam Barnoy @ 2015-05-06 16:45 UTC (permalink / raw)
  To: Jeremy Yallop; +Cc: Oleg Kiselyov, Ömer Sinan Ağacan, Caml List

[-- Attachment #1: Type: text/plain, Size: 3358 bytes --]

Mind blown.

Let's just call this branch... hmm, I dunno, how about 'OCaml 5'?

Sorry for the noise.

On Wed, May 6, 2015 at 11:58 AM, Jeremy Yallop <yallop@gmail.com> wrote:

> On 6 May 2015 at 10:50,  <oleg@okmij.org> wrote:
> > Of course MetaOCaml serialization can be improved. What I'd like to
> > stress is that you don't have to wait for the improvement. You can
> > always, instead of
> >         .<fun u ->  x>.
> > write
> >         .<fun u -> .~(mylift x)>.
> > where
> >         mylift : t -> t code
> > is *your* function that does whatever _you_ like it to do at that
> > particular type t (it should still produce something of the type (t
> > code)).
> >
> > If some particular mylift functions turn out popular, they can be
> > added to MetaOCaml, to save everyone trouble writing them.
> >
> > And I generally agree with Leo that this implicit lifting is
> > baroque. At present I'm not sure if requiring the explicit lifting is
> > too much of a burden. I'm sure that with modular implicits, it won't
> > be.
>
> I've just pushed an OPAM switch for an OCaml compiler that combines
> the MetaOCaml and modular implicits patches, making it possible to
> experiment with explicit user-defined polymorphic CSP.
>
> For example, you might define a signature, CSP, for "things that can
> be persisted":
>
>   module type CSP =
>    sig
>      type t
>      val lift : t -> t code
>   end
>
> together with a top-level function that dispatches to the appropriate
> instance
>
>   let csp (implicit C: CSP) (x : C.t) = C.lift x
>
> and instances of CSP for each type of interest.  Here's an instance
> for the stx type from earlier in the thread:
>
>   implicit module CSP_stx : CSP with type t = stx =
>   struct
>     type t = stx
>
>     let rec lift : stx -> stx code = function
>       | A -> .< A >.
>       | B s -> .< B .~ (lift s) >.
>       | C (s1, s2) -> .< C ( .~(lift s1), .~(lift s2) ) >.
>    end
>
> and here's a parameterised instance for lists that makes it possible
> to persist lists of any persistable element type:
>
>   implicit functor CSP_list(C: CSP) : CSP with type t = C.t list =
>   struct
>     type t = C.t list
>
>     let rec lift : C.t list -> C.t list code = function
>         [] -> .< [] >.
>       | x :: xs -> .< .~(csp x) :: .~(lift xs) >.
>   end
>
> These two instances make it possible to use the CSP function to
> persist stx values, or lists of stx values, or lists of lists of stx
> values (etc.):
>
>    # let ba = B A in .< .~(csp ba) >.;;
>    - : stx code = .<Stx.B Stx.A>.
>
>   # let l = [A; B A] in .< .~(csp l) >.;;
>   - : stx list code = .<[Stx.A; Stx.B Stx.A]>.
>
>   # let ll = [[A; B A]] and ba = B A in .< .~(csp ll), .~(csp ba) >.;;
>   - : (stx list list * stx) code = .<([[Stx.A; Stx.B Stx.A]], (Stx.B
> Stx.A))>.
>
> It's easy to imagine having the csp function built in to MetaOCaml, so
> that we could write .< x >.  (or some similarly convenient syntax) to
> mean .< .~(csp x) >...
>
> You can try out the switch with OPAM in the usual way:
>
>    opam update
>    opam switch 4.02.1+modular-implicits-ber
>    eval `opam config env`
>
> Jeremy.
>
> --
> Caml-list mailing list.  Subscription management and archives:
> https://sympa.inria.fr/sympa/arc/caml-list
> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
> Bug reports: http://caml.inria.fr/bin/caml-bugs
>

[-- Attachment #2: Type: text/html, Size: 4713 bytes --]

^ permalink raw reply	[flat|nested] 23+ messages in thread

end of thread, other threads:[~2015-05-06 16:46 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-04-30 18:36 [Caml-list] Problems with printing MetaOCaml generated code Ömer Sinan Ağacan
2015-04-30 19:52 ` Jacques Carette
2015-04-30 20:25   ` Ömer Sinan Ağacan
2015-04-30 20:57     ` Ömer Sinan Ağacan
2015-04-30 21:35       ` Jeremy Yallop
2015-05-01 11:21       ` oleg
2015-05-01 14:34         ` Ömer Sinan Ağacan
2015-05-01 16:16           ` Leo White
2015-05-01 16:41             ` Ömer Sinan Ağacan
2015-05-01 16:45               ` Leo White
2015-05-01 16:53                 ` Ömer Sinan Ağacan
2015-05-02 18:45                   ` Ömer Sinan Ağacan
2015-05-02 20:49                     ` Jacques Carette
2015-05-03  1:56                       ` Ömer Sinan Ağacan
2015-05-03  2:28                         ` Jacques Carette
2015-05-03  3:19                           ` Ömer Sinan Ağacan
2015-05-03  8:40                             ` Gabriel Scherer
2015-05-03 14:28                               ` Ömer Sinan Ağacan
2015-05-03 15:24                                 ` Leo White
2015-05-03 15:50                                   ` Ömer Sinan Ağacan
2015-05-06  9:50           ` oleg
2015-05-06 15:58             ` Jeremy Yallop
2015-05-06 16:45               ` Yotam Barnoy

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).