English version
Accueil     À propos     Téléchargement     Ressources     Contactez-nous    

Ce site est rarement mis à jour. Pour les informations les plus récentes, rendez-vous sur le nouveau site OCaml à l'adresse ocaml.org.

Browse thread
Camlp4 3.10.0+beta: lists without $list:...$
[ Home ] [ Index: by date | by threads ]
[ Search: ]

[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
Date: 2007-03-23 (16:35)
From: Nicolas Pouillard <nicolas.pouillard@g...>
Subject: Re: [Caml-list] Camlp4 3.10.0+beta: lists without $list:...$
On 3/23/07, Martin Jambon <martin.jambon@ens-lyon.org> wrote:
> I managed to create an object type using camlp4orf:
> let ctyp_object _loc ml =
>    let fields =
>      List.fold_left
>        (fun o (name, typ) ->
>          let m = <:ctyp< $lid:name$ : $typ$ >> in
>          <:ctyp< $o$; $m$ >>)
>        <:ctyp< >> ml in
>    <:ctyp< < $fields$ > >>
> where ml is a list of method declarations of type (string * ctyp) list.
> Before we just had to do this:
> <:ctyp< < $list:ml$ > >>
> Is there anything simpler than my solution? Is a shortcut available?

In fact there is some shortcuts but it was not for all constructions
(fixed now in CVS).

There is functions underlining these shortcuts like Ast.tySem_of_list
that join a list with semicolons.

I can explain briefly the change...

Before there was lists inside the tree. In order to allow a fully
reflective mechanism we now avoid these from the AST.

So there is now many more concrete syntax for any part of the AST
(match branches, let bindings, record field bindings...).

(p, None, e) -> <:match_case< $p$ -> $e$ >>
(p, Some guard, e) -> <:match_case< $p$ when $guard$ -> $e$ >>
(loc, field, true, typ) -> <:ctyp< { $lid:field$ : mutable $typ$ } >>

If m1 and m2 are to match branches (like (p, None, e) for the old one):

<:match_case< $m1$ | $m2$ >>

You want some default cases:

<:match_case< A -> 1 | $m1$ | B x -> x | $m2$ | _ -> assert False >>

So, when one wrote something like:

  let cases = List.mapi (fun i (_,e) -> <:patt< $int:string_of_int i$
>>, None, e) brs in
  let cases = cases @ [<:patt< _ >>, None, <:expr< raise Ulexing.Error >>] in
  let actions = <:expr< match __ulex_state_0 lexbuf with [ $list:cases$ ] >> in

We now can write:

  let cases = List.mapi (fun i (_,e) -> <:match_case< $`int:i$ -> $e$ >>) brs in
  <:expr< match __ulex_state_0 lexbuf with
                 [ $list:cases$
                 | _ -> raise Ulexing.Error ] } >>

Where the error case is inlined in the match directly.

This <:patt< $int:string_of_int i$ >>, None, e is a typical thing
where no syntax were available to it.
Now you can write <:match_case< $`int:i$ -> $e$ >> since any part of
the abstract syntax have a quotation in concrete syntax.

You can note that in `` [ $list:cases$ '' I used the $list:...$
antiquotation that was used to inject some list in a tree. In 3.10 you
can still do that, but  that's a sugar for a function call that will
join all your trees by the proper separator (bar here).

FYI, I've just added all the missing $list:$ sugars to the CVS version
(will be public soon).

> PS: any progress on the manual? It's kind of hard to test new features
> when you don't know what they are.

I agree, but there is still no progress on the documentation :(

BTW, have you read these slides

Nicolas Pouillard