Browse thread
camlp4 & free variables
[
Home
]
[ Index:
by date
|
by threads
]
[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
| Date: | -- (:) |
| From: | Nicolas Pouillard <nicolas.pouillard@i...> |
| Subject: | Re: [Caml-list] camlp4 & free variables |
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