dbuenzli / fmt

OCaml Format pretty-printer combinators
http://erratique.ch/software/fmt
ISC License
71 stars 26 forks source link

Functorize the generic format part. #32

Closed Drup closed 5 years ago

Drup commented 6 years ago

This is sort of an experiment and I'm waiting for your opinion to see if it's worth pursuing/documenting properly.

The context is yet another weird Format hack that I was working on to directly output structured tyxml elements. In this case, I need to create a whole new Format infrastructure (using CamlinternalFormat.make_printf ...) with a new formatter type that is not Format.formatter. Obviously, all the nice convenient printer combinators are not available anymore.

Unless! Most of Fmt is defined on top of kfprintf. This PR refactors the library to make that explicit through a functor that takes the simple signature below, and return most of the combinators.

module type S = sig
  type formatter
  val kfprintf : 
    (formatter -> 'a) ->
    formatter -> ('b, formatter, unit, 'a) format4 -> 'b
end
module Make (F : S) : Fmt_sig.S with type formatter = F.formatter

This new signature contains everything except

The main downside is, of course, going to be the documentation aspect. I think it will be much more tolerable with odoc's signature expansion facilities.

dbuenzli commented 6 years ago

I'm a bit unsure about this. Fundamentally Fmt doesn't buy you much (as you know it's mostly redefs) and the scheme you propose won't allow clients of the non-functorized Fmt interface to use your tyxml aware formatters which is very sad.

I'm pretty sure you know your stuff but isn't there a way to subvert a formatter's functions to achieve what you want so that "regular" formatter definitions can be used with your tyxml backend ? (I'm thinking about https://github.com/ocaml/ocaml/pull/615, but haven't followed closely what this is about).

Drup commented 6 years ago

So, the idea here is really to provide an alternative semantics to format. Applying the Tyxml_fmt combinators on a real formatter wouldn't make sense: the notion of "printing" simply doesn't have the same semantics. The goal of the functorial API for Fmt isn't to make the semantics closer, it's simply to backport the convenience and the familiarity of the Fmt api.

As for trying to reuse the "normal" format ... it's a composability issue. In Lwt_fmt, for example, the type of %a falls back to the "normal" format. This is okay because we're still printing text, and the important bit for lwt is that the underlying actions are asynchronous. For Tyxml_fmt, that is not the case, I want %a to refer to the new formatter type, so that the alternative semantics is used everywhere.

dbuenzli commented 6 years ago

Applying the Tyxml_fmt combinators on a real formatter wouldn't make sense: the notion of "printing" simply doesn't have the same semantics. The goal of the functorial API for Fmt isn't to make the semantics closer, it's simply to backport the convenience and the familiarity of the Fmt api.

Can't help thinking that these two things seems to be contradictory -- is it that the base printing atoms have the same semantics but not the structural elements (boxes) ?

What does fundamentally change in the "printing" notion of Tyxml_fmt, it seems to me that you want to keep the abstract notion of printing that Format provides but only provide an alternate rendering backend.

Do you pretty print content or xml ?

Drup commented 6 years ago

On top of the regular printing and structuring functions, you also can print arbitrary tyxml elements (whose size is 0 unless provided). You can also open and close HTML tags (and the printing will go in the last one open). Such tags are orthogonals to the layout. The output of the printer is of type Html.elt (for any Html module that answers the tyxml signatures).

The goal is to make it easy to define functions that output text-heavy HTML that need some layout formatting. For example if you consider module/type expressions in odoc: you would like some automatic layout, but it's also highly link-ified and span-ified. Many Fmt combinators are still quite useful in this context, in particular the high order ones such as list.

You could argue that outputing the textual representation of HTML is enough for such purposes, and that you could just play around with tags. It's not completely wrong but 1) that's not fun at all 2) by using the abstract representation, I can retarget the printers to other definitions of HTML (the dom tree, virtual dom, etc) or to reactive dom trees (I haven't tried yet, but I'm pretty confident we can make interesting things with it). 3) Tyxml is very useful to define HTML documents, and you want everything to plug decently together.

Drup commented 6 years ago

(This thread in nice. In 2 days, I'm collecting everything, reorder it in a coherent fashion, and I send an abstract to the OCaml workshop)

Drup commented 6 years ago

Well, the OCaml workshop submission was accepted. Have you reached a conclusion? :)

dbuenzli commented 6 years ago

Not really. I'll try to read the sumbmission when I get a bit of time. I'll gladly take a link to it.

dbuenzli commented 5 years ago

One year later I still don't understand what you are trying to achieve (except maybe a resugence of the mistaken Format tags idea). On the web your layout engine is the browser and you control it via css; a fixed laid out output will never do. So I'm closing this.

Drup commented 5 years ago

The point was to allow to format "rich text", aka text with various html tags (bold, color, link) in it. This is not something you do with CSS.

But since the last version of OCaml and the improved support for tags, I don't need this patch anymore. Also, If I remember our discussions correctly at the time, the new tag system would fix most of your issies with it.

dbuenzli commented 5 years ago

The point was to allow to format "rich text", aka text with various html tags (bold, color, link) in it. This is not something you do with CSS.

?!

the new tag system would fix most of your issies with it.

Somehow I doubt. The problem was not its implementation. The problem is that it doesn't make any sense from a semantic point of view (e.g. printing things in red color makes sense in a tty it makes absolutely no sense if you are generating HTML).

Drup commented 5 years ago

Sure, but since now you have isolation/abstraction for the tags, you can just make your tags for your formatter, and be safe in the knowledge that nobody else will be able to use them. Formatter-specific tags are fine and useful.