caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
From: "Nicolas Pouillard" <nicolas.pouillard@inria.fr>
To: "Christophe TROESTLER" <Christophe.Troestler@umh.ac.be>
Cc: caml-list <caml-list@inria.fr>
Subject: Re: [Caml-list] camlp4 & free variables
Date: Fri, 21 Jul 2006 14:01:21 +0200	[thread overview]
Message-ID: <cd67f63a0607210501y1bbb4c63n766d65565ed960fc@mail.gmail.com> (raw)
In-Reply-To: <20060720.163930.91910937.Christophe.Troestler@umh.ac.be>

On 7/20/06, Christophe TROESTLER <Christophe.Troestler@umh.ac.be> wrote:
> On Thu, 20 Jul 2006, "Nicolas Pouillard" <nicolas.pouillard@gmail.com> wrote:
> >
> > On 7/20/06, Christophe TROESTLER <Christophe.Troestler@umh.ac.be> wrote:
> > > Hi,
> > >
> > > Is it possible to write a camlp4 syntax extension that "extract" the
> > > free variables of an expression?
> > You are quite lucky, the camlp4 version has one module to do that!
>
> Thank you very much for your help!  Is there an updated manual for
> camlp4 (if possible written more from a user perspective :)?
>

Alas not now.

> If I understand well your code (I really ought to learn camlp4!)
> FV.free_vars first argument is a set of names which should net be
> considered as free variables.  Is it possible to do it contextually,
> e.g. in
>
>      open_out("X" ^ x)
>
> only "x" is returned as free because "open_out" and "^" are known from
> Pervasives?  Or in
>
>      let z = 1
>      ...
>      FUNCTION(x + z)
>
> only "x" is returned as free because "z" is known from the context?
>

In my previous program, I provide a function f that takes an AST:

f <<let z = x + 2 in x + 2 * y * x * z>>

Here the AST is given using a quotation but there is no relation
between the code outside and inside the quotation so:

let x = 42 in f <<let z = x + 2 in x + 2 * y * x * z>>

This code does not bind x inside the quotation.

Now if you want to use FUNCTION(...) as a sort of macro function there
is a camlp4 filter for that.

Let's call close_expr the this macro function (instead of FUNCTION)

$ cat expression_closure_filter.ml
(* camlp4r *)
#default_quotation "expr";

open Camlp4.PreCast;
open Format;

module FV = Camlp4.Struct.FreeVars.Make Ast;
module S = FV.S;

value _loc = Loc.ghost;

value pervasives =
  let list =
    [ "+"; "-"; "/"; "*" (* ... *) ]
  in List.fold_right S.add list S.empty;

value collect_free_vars_sets =
  object (self)
    inherit FV.fold_free_vars [S.t] S.add ~env_init:pervasives S.empty as super;
    value free_sets = [];
    method set_free free = {< free = free >};
    method expr =
      fun
      [ << close_expr $e$ >> -> (self#expr e)#add_current_free#set_free free
      | e -> super#expr e ];
    method add_current_free = {< free_sets = [ free :: free_sets ] >};
    method free_sets = free_sets;
  end;

value apply_close_expr next_free_set =
  object (self)
    inherit Ast.map as super;
    method expr =
      fun
      [ << close_expr $e$ >> ->
          let e = self#expr e in
          let fv = next_free_set () in
          S.fold (fun x acc -> << fun ~ $x$ -> $acc$ >>) fv e
      | e -> super#expr e ];
  end;

value f st =
  let fv_sets = ref (collect_free_vars_sets#str_item st)#free_sets in
  let next_free_set () =
    match fv_sets.val with
    [ [] -> assert False
    | [x::xs] -> let () = fv_sets.val := xs in x ]
  in (apply_close_expr next_free_set)#str_item st;

AstFilters.register_str_item_filter f;

$ ocamlc -c -pp camlp4rf expression_closure_filter.ml

$ cat test_expression_closure_filter.ml
(* x and y are free *)
close_expr(x y);;

(* bind x *)
let x = 42;;

(* y is free *)
close_expr(x y);;

(* bind y locally so the expr is closed *)
close_expr(let y = x in x y);;

(* bind y locally but outside, z is free *)
let y = x in close_expr(x z y);;

$ camlp4o ./expression_closure_filter.cmo test_expression_closure_filter.ml
(* x and y are free *)
let _ = fun ~y ~x -> x y
(* bind x *)
let x = 42
(* y is free *)
let _ = fun ~y -> x y
(* bind y locally so the expr is closed *)
let _ = let y = x in x y
(* bind y locally but outside, z is free *)
let _ = let y = x in fun ~z -> x z y


> Thanks again -- the new camlp4 version seem to really shine
> w.r.t. the previous one !

Thanks, I'm glad to see camlp4 receive appreciations :)

Cheers,

-- 
Nicolas Pouillard


  parent reply	other threads:[~2006-07-21 12:01 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2006-07-19 23:27 Christophe TROESTLER
2006-07-20  8:28 ` [Caml-list] " Nicolas Pouillard
     [not found]   ` <20060720.163930.91910937.Christophe.Troestler@umh.ac.be>
2006-07-21 12:01     ` Nicolas Pouillard [this message]
2006-07-21 18:16       ` Martin Jambon
2006-07-20  9:25 ` Guido Kollerie
2006-07-20  9:25 ` Guido Kollerie
2006-07-20 10:25   ` Accidentally bounced my email [Was: [Caml-list] camlp4 & free variables] Guido Kollerie
2006-07-20  9:25 ` [Caml-list] camlp4 & free variables Guido Kollerie

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=cd67f63a0607210501y1bbb4c63n766d65565ed960fc@mail.gmail.com \
    --to=nicolas.pouillard@inria.fr \
    --cc=Christophe.Troestler@umh.ac.be \
    --cc=caml-list@inria.fr \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).