From mboxrd@z Thu Jan 1 00:00:00 1970 Received: (from majordomo@localhost) by pauillac.inria.fr (8.7.6/8.7.3) id UAA14663; Fri, 14 Mar 2003 20:32:02 +0100 (MET) X-Authentication-Warning: pauillac.inria.fr: majordomo set sender to owner-caml-list@pauillac.inria.fr using -f Received: from concorde.inria.fr (concorde.inria.fr [192.93.2.39]) by pauillac.inria.fr (8.7.6/8.7.3) with ESMTP id UAA14790 for ; Fri, 14 Mar 2003 20:31:58 +0100 (MET) Received: from viola.sinor.ru (viola.sinor.ru [217.70.106.9]) by concorde.inria.fr (8.11.1/8.11.1) with ESMTP id h2EJVvf00488 for ; Fri, 14 Mar 2003 20:31:57 +0100 (MET) Received: from sibnet.ru (tlg5-ppp77.sibnet.ru [217.70.116.77]) by viola.sinor.ru (8.12.8/8.12.3) with ESMTP id h2EJVhDC024388 for ; Sat, 15 Mar 2003 01:31:43 +0600 Received: by sibnet.ru id m18tutN-001EpZC; Sat, 15 Mar 2003 01:30:57 +0600 (NOVT) Date: Sat, 15 Mar 2003 01:30:57 +0600 From: Max Kirillov To: caml-list@pauillac.inria.fr Subject: Re: [Caml-list] Re: Haskell-like syntax Message-ID: <20030315013056.C5826@max.home> Mail-Followup-To: caml-list@pauillac.inria.fr References: <005d01c2e76f$92d0f8b0$2713f9ca@WARP> <3E6DDAFC.19000.44771B6@localhost> <20030313024153.B748@max.home> <200303122136.12111.oleg_inconnu@myrealbox.com> <20030314003336.D748@max.home> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="ZPt4rx8FFjLCG7dd" Content-Disposition: inline User-Agent: Mutt/1.2.5i In-Reply-To: <20030314003336.D748@max.home>; from max630@mail.ru on Fri, Mar 14, 2003 at 12:33:36AM +0600 X-Sender: Max X-Spam: no; 0.00; kirillov:01 caml-list:01 haskell-like:01 0600,:01 camlp:01 hacks:01 demonstrate:01 'where':99 expr:01 reorder:01 binded:01 gui:01 infer:01 struct:01 pcaml:01 X-Attachments: name="test_where.ml" name="where.ml" name="lazyX.ml" Sender: owner-caml-list@pauillac.inria.fr Precedence: bulk --ZPt4rx8FFjLCG7dd Content-Type: text/plain; charset=us-ascii Content-Disposition: inline On Fri, Mar 14, 2003 at 12:33:36AM +0600, Max Kirillov wrote: > Talking about the single thigs: at the beginning of my way into ocaml, I > did some camlp4 hacks. For example, that was "where" keyword support > (much more powerful than in revised syntax) and some support for "from > top to bottom" style of sources. If you interested, I could post them. I'm sending the changes. Note that, though they are quite stable, I picked them from an environment, so something may broke. A little comment what is it. file test_where.ml -- obvious. Very little, more to demonstrate, than to cover all possible (and really seen) dangers. file lazyX.ml -- misc functions to handle lazy values (see later) note that it is already uses the extension file where.ml -- the main thing There are several things: 1) 'where' notation: ::= where { [rec] } | where [begin] [rec] end the two version are the same (some like {..}, some begin..end). there are some unresolved quastions with prioriries, so, in practice, I often had to use brackets. However, I think that the level I choose is quite reasonable. 2) reorder srt_items there are keyword 'WHERE' (uppercase) in place of structure item. At the point, the structure (or the whole file if at toplevel) is cut, then pieces swapped and concated again. this allows writing: ------- file.ml main ();; WHERE let main () = do_this (); do_that ();; WHERE let do_this () = <.......> and do_that () = <........> ------ 3) lazy values predeclaration ::= [let] [lazy] [rec] this allows define lazy value, which is seen to the whole structure, and not only to the following items. Every value that is binded is lazy value, that, when forced, computes the definition. It uses the LazyX module: nondef () produces the value, set dest src replaces the unforced lazy value dest by the unforced lazy expression src, if any of then is already forced (it is at module initialization time, so it's easy to catch), the exception is raised. I used it in plays with "functional GUI", where needed to declare many inter-depended values and, for various reasons, didn't want to use "let rec <...> and <...>" chain. There is one trouble. When you define a type, and then a lazy value of the type, the compiler complains "the type xxx would escape its scope". this berore it comes to need to infer the type for the initial declaration "let x = LazyX.nondef ()", where it is not yet defined. To solve the problem, I added "HEADER" keyword. It explicitly says that the forward declataions must be placed here instead of beginning of the file. You place it after the type declaration. Of course the lazy values definitions must itself follow the type declarations. The lazy stuff is intended to work only in toplevel, it is not for "struct..end". I used the (1) very much, and would say it quite workable. The (2) is also quite stable, but, now, I would say the realization needs to be changed. The (3) are more a toy than real thing. There could be problems with that. -- Max --ZPt4rx8FFjLCG7dd Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="test_where.ml" let main () = Lazy.force a; Lazy.force b; Lazy.force c; Lazy.force d WHERE lazy c = Int 123 lazy b = String "4567" HEADER lazy a = Int 123 lazy d = match Lazy.force b with Int n -> n | String s -> s2i s where {s2i = int_of_string} WHERE lazy c = Int 123 lazy b = String "4567" WHERE type value = Int of int | String of string --ZPt4rx8FFjLCG7dd Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="where.ml" open Pcaml;; type exprT = MLast.expr Grammar.Entry.e and pattT = MLast.patt Grammar.Entry.e;; let let_gen = Grammar.Entry.create gram "let_general";; let expr_where = Grammar.Entry.create gram "expr_where";; let str_item_semi = Grammar.Entry.create gram "str_item_semi";; let implem_pre = Grammar.Entry.create gram "implem_pre";; let let_lazy_binding = Grammar.Entry.create gram "let_lazy_binding";; let rec insert ?(word="WHERE") elems lst = match lst with [] -> elems | (<:str_item< $str:name$ >>,_ as w)::tl when name=word -> elems@(w::tl) | hd::tl -> hd::insert ~word elems tl let is_header = function <:str_item< value $lid:_$ = LazyX . nondef () >>, _ -> true | _ -> false EXTEND implem: [[ (l,stopped) = implem_pre -> let lst1,lst2 = List.partition is_header l in (List.rev (insert ~word:"HEADER" lst1 lst2),stopped) ]]; implem_pre: [[ "WHERE"; (sil,stopped) = SELF -> ((<:str_item< $str:"WHERE"$ >>,loc)::sil, stopped) | "HEADER"; (sil,stopped) = SELF -> (insert [(<:str_item< $str:"HEADER"$ >>,loc)] sil, stopped) | si = str_item_semi; OPT ";;"; (sil, stopped) = SELF -> (insert si sil, stopped) | "#"; n = LIDENT; dp = OPT expr; ";;" -> ([(<:str_item< # $n$ $opt:dp$ >>, loc)], true) | EOI -> ([], false) ]]; str_item_semi: [[ si = str_item; OPT ";;" -> match si with <:str_item< LazyX.set $lid:dest$ $e$ >> as si -> [(<:str_item< value $lid:dest$ = LazyX . nondef () >>,loc);(si, loc)]; | _ -> [(si, loc)] ]]; str_item: LEVEL "top" [[ "let"; "lazy"; lb = let_lazy_binding -> lb | "lazy"; lb = let_lazy_binding -> lb]]; let_lazy_binding: [[ lb = let_binding -> let tr (p,e) = match p with <:patt< $lid:name$ >> -> <:str_item< LazyX.set $lid:name$ ( lazy $e$ ) >> | _ -> raise Stream.Failure in tr lb ]]; expr: BEFORE "top" [[ e = SELF; (ifRec,l) = expr_where -> <:expr< let $rec:ifRec!=None$ $list:l$ in $e$ >> ]]; expr_where: [["where"; _ = OPT "begin"; (ifRec,l) = let_gen; "end" -> (ifRec,l) | "where"; "{"; (ifRec,l) = let_gen; "}" -> (ifRec,l) ]]; let_gen: [[r = OPT "rec"; l = LIST1 let_binding SEP "and" -> (r,l)]]; module_expr: [[ "struct"; st = LIST0 [ "WHERE" -> `Where | s = str_item; OPT ";;" -> `Item s ]; "end" -> let rec f ((il::ils) as ilS:'a list list) = function [] -> ilS | (`Item i::l) -> f ((i::il)::ils) l | (`Where::l) -> f ([]::ilS) l in let s = <:str_item< $lid:"b"$ = $lid:"a"$ >> in <:module_expr< struct $list:(List.concat (List.map List.rev (f [[]] st)))$ end >> ]]; END;; --ZPt4rx8FFjLCG7dd Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="lazyX.ml" exception Already_forced let nondef () = lazy ( raise Lazy.Undefined ) let set (dest:'a Lazy.t) (src:'a Lazy.t) = (if Obj.tag dobj <> Obj.lazy_tag || Obj.tag sobj <> Obj.lazy_tag then raise Already_forced else Obj.set_field dobj 0 (Obj.field sobj 0)) where {dobj = Obj.repr dest and sobj = Obj.repr src} --ZPt4rx8FFjLCG7dd-- ------------------- To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/ Beginner's list: http://groups.yahoo.com/group/ocaml_beginners