From: Alain F. <fr...@cl...> - 2001-11-18 19:08:53
|
Hello, I worked a little bit on htmlgen and wrote a new code generator. The concrete type for documents is: type 'a t = | Pcdata of string | Verbatim of string | EmptyElement of string * attrs | Element of string * attrs * 'a t list | Extension of 'a and attrs = (string * string) list This definition allows fast construction of the document tree and is not specific to a DTD. The Extension constructor allows to add information that is not part of the HTML document (an alternative would have been to add an extension value to each node, but for the applications I have in mind, Extensions nodes should be rare enough to not justify the overhead). EmptyElement represents elements without closing tag, such as <hr>, <br>,... (and some <p>). Pcdata nodes may contain special characters that HTML requires to escape, such as &, <, ... The generated module (Loose) uses a type: type ('a,'b) t = 'a Html.t where 'b is used to enforce DTD constraints. Constructors look like: val pcdata_ : string -> ('a,[> `Pcdata]) t val textarea_ : ?id:string -> ?class_:string -> ?style:string -> ?title:string -> ?lang:string -> ?dir:string -> ?onclick:string -> ?ondblclick:string -> ?onmousedown:string -> ?onmouseup:string -> ?onmouseover:string -> ?onmousemove:string -> ?onmouseout:string -> ?onkeypress:string -> ?onkeydown:string -> ?onkeyup:string -> ?name:string -> ?disabled:string -> ?readonly:string -> ?tabindex:int -> ?accesskey:string -> ?onfocus:string -> ?onblur:string -> ?onselect:string -> ?onchange:string -> rows:int -> cols:int -> ('a,[< `Pcdata ]) t -> ('a,[> `Textarea]) t val frameset_ : ?id:string -> ?class_:string -> ?style:string -> ?title:string -> ?rows:string -> ?cols:string -> ?onload:string -> ?onunload:string -> ('a,[< `Frameset | `Frame ]) t list -> ('a,[< `Noframes ]) t option -> ('a,[> `Frameset]) t (optional) attributes becomes (optional) labeled arguments; for the moment, they all have type string except for NUMBER attributes which are int. The submodes are passed as one or several (for very few tags, such as frameset above) arguments. Types are somewhat simpler than those of the previous code generators. The .mli is no longer produced with ocamlc -i, so it should work with OCaml 3.01 now (its type pretty printer truncated long types). I also rewrote Gui to work with Loose.t documents (it used to produce HTML output by a sequence of prints), file gui_dtd.ml in the CVS. It implements various dynamic type checkings, that can detect if you forget to display a widget (or if you display it twice, or in the wrong form); these checks are done by placing Extension nodes in the document tree to keep track of widgets and containers in the document. There is a difficulty: the DTD validation trick of htmlgen relies on row polymorphism with polymorphic variants. As widgets are objects, their html method must be monomorphic. The good news is that you normally use these method only once, so we can parametrize widgets class with type variables constraining the html method type. In some situation, one may want to use the method twice with different types (if the HTML generation has some conditionals), and in this situation, an (OCaml) coercion is necessary. The bad news is that the interface of the module is ugly, with lots of spurious class parameters (try ocamlc -c -i dtd_gui.ml). No doubt that life would be even more beautiful with polymorphic methods in OCaml. Here is an example demonstrating the new API: let rec page = "page", fun app -> (* Build the page model *) let cgi = Application.cgi app in let dialog = new dialog app () in let form = new form dialog "form" in let set = new text_field form "set" in let submit = new submit form "submit" (fun () -> let n = int_of_string (set # value) in Application.activate app page n) in let current = new hidden_field form "current" in let increment = new submit form "increment" (fun () -> let n = int_of_string (current # value) in Application.activate app page (n+1)) in let reinit = new submit form "reinit" (fun () -> Application.activate app page 0) in fun n -> (* Build the page layout *) send cgi ( dialog # html "A counter" [ pcdata_ (Printf.sprintf "Counter: %i" n); form # html [ current # html (string_of_int n); submit # html "Set to:"; set # html (); br_ (); increment # html "++"; reinit # html "Reinit" ] ] ) (running at: http://www.eleves.ens.fr:8080/cgi-bin/frisch/gui_dtd.cgi ) The (send cgi ...) is there because I haven't modified the Application module yet. Note that it is possible to build the html out of order (dynamic checks are done at when the whole HTML document is build): let f = form # html [ current # html (string_of_int n); submit # html "Set to:"; set # html (); br_ (); increment # html "++"; reinit # html "Reinit" ] in dialog # html "A counter" [ pcdata_ (Printf.sprintf "Counter: %i" n); f ] What do people think of the HTML production with DTD validation ? Is it viable ? Should it be integrated in the core Bedouin application model ? Alain |
From: Patrick M D. <pa...@wa...> - 2001-11-20 14:38:47
|
Hello Alain, On Sun, 18 Nov 2001, Alain Frisch wrote: > The concrete type for documents is: > > type 'a t = > | Pcdata of string > | Verbatim of string > | EmptyElement of string * attrs > | Element of string * attrs * 'a t list > | Extension of 'a > and attrs = (string * string) list Having a type like this is very important for abstract construction of documents. Do you think it is appropriate to be able to represent these within your structure: - SGML escapes (e.g. <!DOCTYPE ..> or <!-- comments --> *) - Processing instructions (<? ... ?>) > The Extension constructor allows to add information that is not part of > the HTML document (an alternative would have been to add an extension > value to each node, but for the applications I have in mind, Extensions > nodes should be rare enough to not justify the overhead). Good idea. > Types are somewhat simpler than those of the previous code generators. > The .mli is no longer produced with ocamlc -i, so it should work with > OCaml 3.01 now (its type pretty printer truncated long types). Definitely, it is much easier to follow and understand what is going on. > There is a difficulty: the DTD validation trick of htmlgen relies on row > polymorphism with polymorphic variants. As widgets are objects, their html > method must be monomorphic. The good news is that you normally use these > method only once, so we can parametrize widgets class with type variables > constraining the html method type. In some situation, one may want to use > the method twice with different types (if the HTML generation has some > conditionals), and in this situation, an (OCaml) coercion is necessary. > > The bad news is that the interface of the module is ugly, > with lots of spurious class parameters (try ocamlc -c -i dtd_gui.ml). > No doubt that life would be even more beautiful with polymorphic methods > in OCaml. This may suggest that we don't want to use objects here, but Jacques' post was encouraging. > The (send cgi ...) is there because I haven't modified the > Application module yet. Note that it is possible > to build the html out of order (dynamic checks are done at > when the whole HTML document is build): If you're interested, I'll update the other files in the proposal directory as well. > What do people think of the HTML production with DTD validation ? > Is it viable ? Should it be integrated in the core Bedouin > application model ? I think this looks very good. I plan on updating the CVS webapp soon to use Netcgi and Htmlgen features to see how they feel in practice. Patrick |
From: Alain F. <fr...@cl...> - 2001-11-20 23:00:20
|
On Tue, 20 Nov 2001, Patrick M Doane wrote: > > The concrete type for documents is: > > > > type 'a t = > > | Pcdata of string > > | Verbatim of string > > | EmptyElement of string * attrs > > | Element of string * attrs * 'a t list > > | Extension of 'a > > and attrs = (string * string) list > > Having a type like this is very important for abstract construction of > documents. Do you think it is appropriate to be able to represent these > within your structure: > > - SGML escapes (e.g. <!DOCTYPE ..> or <!-- comments --> *) > - Processing instructions (<? ... ?>) Processing instructions aren't part of HTML, and are rarely used in XML documents, as far as I can tell. The <!DOCTYPE ..> is somewhat special in the sense that it may appear only at the beginning; Bedouin could send it automatically when it knows that the request result is an HTML page. Comments can always be added as Verbatim nodes; I don't see the need to have a special constructor for them. It would a good idea to start discussing/designing a template system; I can imagine an extra constructor : Template of ((string -> html) -> html) which produces an html fragment when it is given a "hole filling" function. Now there could be alternative 'constructor' for widgets, that fill holes instead of returning an html 'method'. There should be a way to enforce that holes are filled exactly once, so the (string -> html) is maybe not adequate. Mmmh, on second thought, I don't see how form widgets could fit in this approach (they have to update the <form> tag of an html fragment). > This may suggest that we don't want to use objects here, but Jacques' post > was encouraging. Encouraging, but I wouln't hold my breath ... > > The (send cgi ...) is there because I haven't modified the > > Application module yet. Note that it is possible > > to build the html out of order (dynamic checks are done at > > when the whole HTML document is build): > > If you're interested, I'll update the other files in the proposal > directory as well. The API is probably going to change again, but it may be a good idea in order to find weakness in the proposal ... > > What do people think of the HTML production with DTD validation ? > > Is it viable ? Should it be integrated in the core Bedouin > > application model ? > > I think this looks very good. I plan on updating the CVS webapp soon to > use Netcgi and Htmlgen features to see how they feel in practice. Great. Alain |
From: Patrick M D. <pa...@wa...> - 2001-11-21 04:40:29
|
On Wed, 21 Nov 2001, Alain Frisch wrote: > Processing instructions aren't part of HTML, and are rarely used in > XML documents, as far as I can tell. The <!DOCTYPE ..> is somewhat special > in the sense that it may appear only at the beginning; Bedouin could send > it automatically when it knows that the request result is an HTML page. > Comments can always be added as Verbatim nodes; I don't see the need to > have a special constructor for them. I agree that all of these can be handled through verbatim nodes. BTW, processing instructions are allowed but still discouraged. See B.3.6 of the HTML 4 spec for more details. > It would a good idea to start discussing/designing a template system; > I can imagine an extra constructor : > Template of ((string -> html) -> html) > > which produces an html fragment when it is given a "hole filling" > function. Now there could be alternative 'constructor' for widgets, > that fill holes instead of returning an html 'method'. There should > be a way to enforce that holes are filled exactly once, so the (string -> > html) is maybe not adequate. One problem is that these holes are likely to be HTML fragments. It would be nice if I could still make use of the typing constraints and not represent as a string. So maybe a template is simply a Caml function that produces Html.t types. <html> <head>$title</head> <body> <table> <caption>$table_caption</caption> <tbody>$table_data</tbody> </table> </body> </html> Is translated into the function: val template : title:('a, [< `Title]) t -> table_caption:('a, [< inline]) t list -> table_data:('a, [< `Tr]) t list -> ('a, [> `Html]) t > > This may suggest that we don't want to use objects here, but Jacques' post > > was encouraging. > > Encouraging, but I wouln't hold my breath ... At the very least, we definitely should take advantage of Jacques' new variant syntax. I'm not familiar with the dtd generator, but could you easily modify it to output definitions like these: type fontstyle = [ `Tt | `I | `B | `U | `S | `Strike | `Big | `Small ] type phrase = [ `Em | `Strong | `Dfn | `Code | `Samp | `Kbd | `Var | `Cite | `Abbr | `Acronym ] ... type inline = [ pcdata | fontstyle | phrase | special | formctl ] ... type flow = [ inline | block ] These variant types can be referred to by name in the function signatures. It makes a real improvement on the quality of error messages. Too bad there isn't a similar syntax to improve the handling of attributes. > > If you're interested, I'll update the other files in the proposal > > directory as well. > > The API is probably going to change again, but it may be a good idea in > order to find weakness in the proposal ... That's okay. I figured as much but thought it would be a good chance to get some experience with the new stuff. > > I think this looks very good. I plan on updating the CVS webapp soon to > > use Netcgi and Htmlgen features to see how they feel in practice. > > Great. I spent some time hacking tonight and have some comments so far: - Overall it's very nice to use as a way to ensure correctness. - Support for verbatim_ is crucial as it allows for an easy way to migrate an application to the new model. - List types may not be the best choice for sub-elements. It seems that I often need to concatenate two lists together. - There is no difference between elem* and elem+ as represented in the DTD. Perhaps a simple phantom type tracking between `Empty and `Nonempty could work here? - Error messages are a bit verbose. Using the new polymorphic variant syntax helps with this. - Why do all elements have the '_' suffix and only attributes that match keywords have the '_' suffix? - Boolean attributes need to be minimized when printing <option selected="selected"> should simply be <option selected> Otherwise it may confuse some user agents. - Elements like tables that have many unlabelled arguments can be annoying to use. Patrick |
From: Kevin G. <kg...@au...> - 2001-11-21 05:24:29
|
> - Boolean attributes need to be minimized when printing > > <option selected="selected"> should simply be > > <option selected> > > Otherwise it may confuse some user agents. For any XHTML 1.0-transitional document, Boolean attributes are indeed represented redundantly. The DOCTYPE should be consulted for this - we can' t choose one or the other, if the DOCTYPE really is XHTML 1.0, it should use the form <option selected="selected">. Conversely, if the document type is HTML 3.2, we *could* use <option selected>. There may be user agents that are confused by newer markup...however, there are actually some agents on the flipside of that, that complain if a document's markup doesn't match its DOCTYPE (iCab on the Macintosh, for instance). I think browsers have matured enough that it's best to make the markup perfectly match the specification referenced by the DOCTYPE. Kevin G. |
From: Patrick M D. <pa...@wa...> - 2001-11-21 06:04:08
|
On Tue, 20 Nov 2001, Kevin Grant wrote: > > - Boolean attributes need to be minimized when printing > > > > <option selected="selected"> should simply be > > > > <option selected> > > > > Otherwise it may confuse some user agents. > > For any XHTML 1.0-transitional document, Boolean attributes are indeed > represented redundantly. The DOCTYPE should be consulted for this - we can' > t choose one or the other, if the DOCTYPE really is XHTML 1.0, it should > use the form <option selected="selected">. Conversely, if the document > type is HTML 3.2, we *could* use <option selected>. > > There may be user agents that are confused by newer markup...however, there > are actually some agents on the flipside of that, that complain if a > document's markup doesn't match its DOCTYPE (iCab on the Macintosh, for > instance). I think browsers have matured enough that it's best to make the > markup perfectly match the specification referenced by the DOCTYPE. Hmm... good point. Here's a relevant excerpt from the 4.01 standard: In HTML, boolean attributes may appear in minimized form -- the attribute's value appears alone in the element's start tag. Thus, selected may be set by writing: <OPTION selected> instead of: <OPTION selected="selected"> Authors should be aware that many user agents only recognize the minimized form of boolean attributes and not the full form. So it looks like we may want to have some intelligence about the attribute minimization. Unfortunately, the DTD does not specify this information. It's only located in the SGML declaration as the SHORTTAG feature. I think it would be overkill to start processing SGML declarations simply to get at this information though. Maybe we should add an option to the DTD generator so that the output modules can specify the minimization information? Or is anyone aware of an SGML declaration parser in Caml? ;) Patrick |
From: Alain F. <fr...@cl...> - 2001-11-21 12:53:56
|
On Tue, 20 Nov 2001, Patrick M Doane wrote: > So maybe a template is simply a Caml function that produces Html.t types. > > <html> > <head>$title</head> > <body> > <table> > <caption>$table_caption</caption> > <tbody>$table_data</tbody> > </table> > </body> > </html> > > Is translated into the function: > > val template : > title:('a, [< `Title]) t -> > table_caption:('a, [< inline]) t list -> > table_data:('a, [< `Tr]) t list -> > ('a, [> `Html]) t Ok for 'data' holes. What about widgets ? For forms, the HTML author will insert in the template a dummy <form> element, which has to be patched by the corresponding form widget; same thing for form fields. Also, IIRC, it has been expressed that modifying the templates should not oblige to recompile the program (altough I don't see the difference in difficulty between running a validation tool and typing 'make'). If we don't impose ourself this restriction, we can do nice things, such as providing the template system simply as a CamlP4 extension. > At the very least, we definitely should take advantage of Jacques' new > variant syntax. Done. A flag in dtd.ml (do_abbrev) turns this feature on. As I don't have OCaml 3.03 on all the systems I work on, I prefer not to activate it by default. > It makes a real improvement on the quality of error messages. Sure. > Too bad > there isn't a similar syntax to improve the handling of attributes. Another option would be pass the attributes as a list (and this avoid traversing all the possible attributes for each tag constructor). But there would be no way to enforce that attributes appears at most once. > I spent some time hacking tonight and have some comments so far: > > - List types may not be the best choice for sub-elements. It seems > that I often need to concatenate two lists together. Ok, maybe trees (optimized to inject lists and singletons) ? type 'a tree = Node of 'a tree list | One of 'a | Many of 'a list;; > - There is no difference between elem* and elem+ as represented in the > DTD. Perhaps a simple phantom type tracking between `Empty and > `Nonempty could work here? You mean defining a new type list (or tree) using polymorphic variants: type 'a list_ = [ `Cons of ('a * 'a list_) | `Empty ] and provide a number of concatenation functions that prove that the concatenation is non-empty as soon as one of the arguments is non-empty ? 3 functions would be needed, of types: 'a list_ * 'a list_ -> 'a list_ [`Cons of ('a * 'a list)] * 'a list -> [`Cons of ('a * 'a list)] 'a list * [`Cons of ('a * 'a list)] -> [`Cons of ('a * 'a list)] (oh, thank you, you just suggested a good example of conjunctive types in functions declaration for the type system I study :-) ). > - Error messages are a bit verbose. Using the new polymorphic variant > syntax helps with this. Verbose and more explicit. Otherwise, the programmer has to know the entities used in the DTD to abbreviate variants. > - Why do all elements have the '_' suffix and only attributes that > match keywords have the '_' suffix? Because elements constructors pollute the namespace (and moreover, with identifiers that one may want to use). If uniformity is important, I suggest adding '_' to all the attribute. Do you agree ? > - Elements like tables that have many unlabelled arguments can > be annoying to use. Nothing prevents from providing a set of hand-made element constructors, that can add or remove labelled arguments, fix attribute values (for instance input_ type:`Submit), etc ... to match typical use. For tables, a simple (('a,[< ...]) list list -> ('a,[> `Table]) t) could be useful for instance. |
From: Patrick M D. <pa...@wa...> - 2001-11-21 17:07:58
|
On Wed, 21 Nov 2001, Alain Frisch wrote: > On Tue, 20 Nov 2001, Patrick M Doane wrote: > > Ok for 'data' holes. What about widgets ? For forms, the > HTML author will insert in the template a dummy <form> element, which has > to be patched by the corresponding form widget; same thing for > form fields. From what I can tell, a widget is essentially two functions. One produces HTML and the other gets the value for the widget. Shouldn't it be possible to call the HTML generating function and pass it in as a data hole? > Also, IIRC, it has been expressed that modifying the templates should not > oblige to recompile the program (altough I don't see the difference in > difficulty between running a validation tool and typing 'make'). If we > don't impose ourself this restriction, we can do nice things, such > as providing the template system simply as a CamlP4 extension. I feel that recompilation probably makes the most sense. It's at least more in the spirit of Caml to check things statically then to have the program fail at runtime because the template is no longer compatible. Nice systems can always be built around 'make' too if this were ever an issue. > > At the very least, we definitely should take advantage of Jacques' new > > variant syntax. > > Done. A flag in dtd.ml (do_abbrev) turns this feature on. As I don't > have OCaml 3.03 on all the systems I work on, I prefer not to activate > it by default. A flag seems a good idea. I have been tracking the alpha version for awhile because I want to play around with the new Ocamldoc tool. > > Too bad > > there isn't a similar syntax to improve the handling of attributes. > > Another option would be pass the attributes as a list (and this avoid > traversing all the possible attributes for each tag constructor). But > there would be no way to enforce that attributes appears at most > once. I think the current approach models the semantics best. The "problem" right now is there is no way to factor out common arguments to a function. For example, f and g are not the same: type t = a -> b val f : a -> b -> c -> d val g : t -> c -> d There are times where I would like to make f and g equivalent. Creating type abbreviations for attribute sets is a good example of that here. > > I spent some time hacking tonight and have some comments so far: > > > > - List types may not be the best choice for sub-elements. It seems > > that I often need to concatenate two lists together. > > Ok, maybe trees (optimized to inject lists and singletons) ? > > type 'a tree = Node of 'a tree list | One of 'a | Many of 'a list;; This would be the appropriate representation. There is a tradeoff between efficiency and syntax though. It's currently very readable to have: p_ [ pcdata_ "...."; b_ [pcdata_ "..."]; pcdata_ "..."; ]; One other alternative would be to extend the Html.t type to have some kind of List constructor. So we could write: p_ [ pcdata_ "..."; list_ (List.map pcdata_ [".."; ".."]); pcdata_ "..."; ]; What do you think of that approach? > > - There is no difference between elem* and elem+ as represented in the > > DTD. Perhaps a simple phantom type tracking between `Empty and > > `Nonempty could work here? > > You mean defining a new type list (or tree) using polymorphic variants: > > type 'a list_ = [ `Cons of ('a * 'a list_) | `Empty ] > > and provide a number of concatenation functions that prove that > the concatenation is non-empty as soon as one of the arguments > is non-empty ? 3 functions would be needed, of > types: > > 'a list_ * 'a list_ -> 'a list_ > [`Cons of ('a * 'a list)] * 'a list -> [`Cons of ('a * 'a list)] > 'a list * [`Cons of ('a * 'a list)] -> [`Cons of ('a * 'a list)] This might be a bit cumbersome to use, but that's the idea. I was actually thinking you might restrict the concatenation function to require that one of the arguments was non-empty. Maybe something like this: type ('a,'b) t (* abstract type that corresponds to 'a list *) val empty : ('a, [> `Empty]) t val cons : 'a -> ('a, 'b) t -> ('a, [> `Nonempty]) t val hd : ('a, [> `Nonempty]) t -> 'a val concat : ('a, 'b) t -> ('a, [> `Nonempty]) t -> ('a, [> `Nonempty]) t It's not as flexible, but it might work okay in practice. Probably not though. > (oh, thank you, you just suggested a good example > of conjunctive types in functions declaration for the type > system I study :-) ). I'm definitely interested in chatting about new type systems and possible examples, glad to help! :) > > - Error messages are a bit verbose. Using the new polymorphic variant > > syntax helps with this. > > Verbose and more explicit. Otherwise, the programmer has to know the > entities used in the DTD to abbreviate variants. Yes, I agree. Although sometimes verbose in the wrong way. For example, if the function expects a list, and I only passed a single element, then I don't care about what entities are allowed in the list yet. Use of type abbreviations removed most of the poor error messages that I saw. > > - Why do all elements have the '_' suffix and only attributes that > > match keywords have the '_' suffix? > > Because elements constructors pollute the namespace (and moreover, > with identifiers that one may want to use). If uniformity is important, > I suggest adding '_' to all the attribute. Do you agree ? This is a good justification - I don't think that uniformity is the most important thing. > > - Elements like tables that have many unlabelled arguments can > > be annoying to use. > > Nothing prevents from providing a set of hand-made element constructors, > that can add or remove labelled arguments, fix attribute values > (for instance input_ type:`Submit), etc ... to match typical use. > For tables, a simple (('a,[< ...]) list list -> ('a,[> `Table]) t) > could be useful for instance. Absolutely. The current approach seems to make the most sense to me. Patrick |
From: Alain F. <fr...@cl...> - 2001-11-21 22:23:46
|
On Wed, 21 Nov 2001, Patrick M Doane wrote: > >From what I can tell, a widget is essentially two functions. One produces > HTML and the other gets the value for the widget. Some widgets don't have a value method (forms, buttons, links). > Shouldn't it be possible > to call the HTML generating function and pass it in as a data hole? You mean filling the hole with the result of the function ? But in the template, it is more a placeholder than a hole: for an input field, the element <INPUT ...> is already present, and it just has to be patched (to add current value, define its name); for forms, the template engine has to keep the content of the element in the template. Of course, all this holds if we want templates to be html documents on their own (to be able to use HTML editors). > > Also, IIRC, it has been expressed that modifying the templates should not > > oblige to recompile the program (altough I don't see the difference in > > difficulty between running a validation tool and typing 'make'). If we > > don't impose ourself this restriction, we can do nice things, such > > as providing the template system simply as a CamlP4 extension. > > I feel that recompilation probably makes the most sense. It's at least > more in the spirit of Caml to check things statically then to have the > program fail at runtime because the template is no longer compatible. No need to say I second that, but I can understand that people wouln't want to recompile the whole application to just change a word in a static text. What's the opinion of people reading the list ? (desperate attempt to get feedback from the silent majority) > I think the current approach models the semantics best. The "problem" > right now is there is no way to factor out common arguments to a function. > For example, f and g are not the same: > > type t = a -> b > > val f : a -> b -> c -> d > val g : t -> c -> d > > There are times where I would like to make f and g equivalent. Creating > type abbreviations for attribute sets is a good example of that here. I don't get the point; what does "f and g equivalent" mean ? If this is just about factoring types in the interface, one can use: type 'a events = ?onclick:string -> ?ondblclick:string -> ?onmousedown:string -> ?onmouseup:string -> ?onmouseover:string -> ?onmousemove:string -> ?onmouseout:string -> ?onkeypress:string -> ?onkeydown:string -> ?onkeyup:string -> 'a > One other alternative would be to extend the Html.t type to have some kind > of List constructor. So we could write: > > p_ [ > pcdata_ "..."; > list_ (List.map pcdata_ [".."; ".."]); > pcdata_ "..."; > ]; Mmmh, done (I called it seq_), but it should be marked as unsafe: it breaks DTD constraints as it allows to use a list where a single element is expected (such as a list of `Body where a single is expected). However, it seems that there are two kind of elements in HTML: the ones that can always be duplicated in their super-element, and the ones that can never be duplicated (TITLE, BASE, BODY, "CDATA") - is it true ? - and so we could restrict seq_ to the first kind of elements. > This might be a bit cumbersome to use, but that's the idea. I was actually > thinking you might restrict the concatenation function to require that one > of the arguments was non-empty. Maybe something like this: > > type ('a,'b) t (* abstract type that corresponds to 'a list *) > > val empty : ('a, [> `Empty]) t > val cons : 'a -> ('a, 'b) t -> ('a, [> `Nonempty]) t > val hd : ('a, [> `Nonempty]) t -> 'a > val concat : ('a, 'b) t -> ('a, [> `Nonempty]) t -> ('a, [> `Nonempty]) t > > It's not as flexible, but it might work okay in practice. Probably not > though. Usually, for instance in order to fill a table by the results of a computation, the data will come from a standard Caml list; there should be a way to convert them to this representation and dynamically checks emptyness ... I fear that checking statically the non-emptyness may complicate the types too much for the benefit, but I don't have a strong opinion on it. > > > - Error messages are a bit verbose. Using the new polymorphic variant > > > syntax helps with this. > > > > Verbose and more explicit. Otherwise, the programmer has to know the > > entities used in the DTD to abbreviate variants. > > Yes, I agree. Although sometimes verbose in the wrong way. For example, if > the function expects a list, and I only passed a single element, then I > don't care about what entities are allowed in the list yet. Use of type > abbreviations removed most of the poor error messages that I saw. Ok, good point. It is better to have compact error types in general, and refer to the DTD / interface when needed. Alain |
From: Gerd S. <in...@ge...> - 2001-12-07 16:34:10
|
On 2001.11.21 18:07 Patrick M Doane wrote: > On Wed, 21 Nov 2001, Alain Frisch wrote: > > Also, IIRC, it has been expressed that modifying the templates should not > > oblige to recompile the program (altough I don't see the difference in > > difficulty between running a validation tool and typing 'make'). If we > > don't impose ourself this restriction, we can do nice things, such > > as providing the template system simply as a CamlP4 extension. > > I feel that recompilation probably makes the most sense. It's at least > more in the spirit of Caml to check things statically then to have the > program fail at runtime because the template is no longer compatible. > > Nice systems can always be built around 'make' too if this were ever an > issue. Well, it was my whish to have templates outside of the executable. I have some experiences with computer centers, and it is often difficult and time- consuming to get executables updated (you have to repeat the whole test series). Maybe there is a compromise. At least for the bytecode compiler, it is no problem to load cmo files dynamically (and for native executables, there is a solution, too). Could this be a way to update templates? Unfortunately, this requires that there is a registry for templates, because you cannot call loaded functions directly. And this restricts the possible types of templates (must be a monomorphic fixed type). Example: Html.t list -> Html.t or something like that. But then a lot of type information is again lost. The next idea is a stub generator. Templates in the registry would have the type (int * (Html.t list -> Html.t)) where the int is the number of arguments. But the templates are used as n-ary functions Html.t -> ... -> Html.t. The generator creates code that enters templates into the registry, and code that pulls templates out of the registry and retypes as n-ary function. What do you think about it? If too complicated I don't insist on loadable templates. Gerd -- ---------------------------------------------------------------------------- Gerd Stolpmann Telefon: +49 6151 997705 (privat) Viktoriastr. 45 64293 Darmstadt EMail: ge...@ge... Germany ---------------------------------------------------------------------------- |
From: Patrick M D. <pa...@wa...> - 2001-12-07 16:56:54
|
On Fri, 7 Dec 2001, Gerd Stolpmann wrote: > On 2001.11.21 18:07 Patrick M Doane wrote: > > On Wed, 21 Nov 2001, Alain Frisch wrote: > > > Also, IIRC, it has been expressed that modifying the templates should not > > > oblige to recompile the program (altough I don't see the difference in > > > difficulty between running a validation tool and typing 'make'). If we > > > don't impose ourself this restriction, we can do nice things, such > > > as providing the template system simply as a CamlP4 extension. > > > > I feel that recompilation probably makes the most sense. It's at least > > more in the spirit of Caml to check things statically then to have the > > program fail at runtime because the template is no longer compatible. > > > > Nice systems can always be built around 'make' too if this were ever an > > issue. > > Well, it was my whish to have templates outside of the executable. I have > some experiences with computer centers, and it is often difficult and time- > consuming to get executables updated (you have to repeat the whole test > series). You're right - there can be an unwarranted fear about changing an executable. Why this doesn't extend to changing something like a Perl script, I don't understand. So, if a template is always guaranteed to be valid (by whatever means we define for that), then this should be fine. I just wouldn't want to see errors from the Ocaml type checker popping up in the web page in the case of a template error. The other advantage to compilation is performance so we may want to consider both routes. > Maybe there is a compromise. At least for the bytecode compiler, it is no > problem to load cmo files dynamically (and for native executables, there is > a solution, too). Could this be a way to update templates? Perhaps those who want to compile templates are also willing to rebuild the executable? This would keep the architecture simpler. For regular usage, the templates would then be interpreted directly, or preprocessed into a custom binary form. > Unfortunately, this requires that there is a registry for templates, > because you cannot call loaded functions directly. And this restricts > the possible types of templates (must be a monomorphic fixed type). > Example: Html.t list -> Html.t or something like that. But then a lot > of type information is again lost. Yes, it would be nice if dynamic functions could be called, rather than registered. > The next idea is a stub generator. Templates in the registry would > have the type (int * (Html.t list -> Html.t)) where the int is the > number of arguments. But the templates are used as n-ary functions > Html.t -> ... -> Html.t. The generator creates code that enters > templates into the registry, and code that pulls templates out of the > registry and retypes as n-ary function. How would it do that retyping dynamically? I guess if we arbitrarily limit the number of arugments, I see how this could be done. As an aside comment, templates may want to receive more than one element in a hole, so should add the type: Html.fragment = Html.t list and then have templates operate on fragments? Patrick |
From: Patrick M D. <pa...@wa...> - 2001-11-21 17:21:30
|
On Wed, 21 Nov 2001, Alain Frisch wrote: > Done. A flag in dtd.ml (do_abbrev) turns this feature on. As I don't > have OCaml 3.03 on all the systems I work on, I prefer not to activate > it by default. I think that the new option does not consider Must_not_occur cases properly. For example form_ will allow any flow object inside when it should now allow nested forms. I'm not aware of any way to represent the Must_not_occur information nicely in the polymorphic variant syntax. Otherwise, we could fall back to enumerating all the tags explicitly. In that case it would still be nice to reuse the "inline" type abbreviation since all those variants are still allowed. Patrick |