caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* [Caml-list] I never succeeded in using Format
@ 2014-03-06 16:34 Matthieu Dubuget
  2014-03-06 16:46 ` Jeremy Yallop
  2014-03-06 16:47 ` Benoit Vaugon
  0 siblings, 2 replies; 12+ messages in thread
From: Matthieu Dubuget @ 2014-03-06 16:34 UTC (permalink / raw)
  To: caml-list

Is the following behaviour expected, or a misunderstanding of mine?

In short, I'd like to use the Format module to prepare an
output inside a Buffer.t. But a basic <hov> box does not
break lines as I would expect, while printf does.

OCaml version 4.01.0

# open Format;;
# printf "@[<hov0>111,@,222,@,333,@,444,@,555,@,666@]@.";;
111,222,333,444,555,666
- : unit = ()
# set_margin 9;;
- : unit
= ()
# printf "@[<hov0>111,@,222,@,333,@,444,@,555,@,666@]@.";;
111,222,
333,444,
555,666
- : unit
= ()
# sprintf "@[<hov0>111,@,222,@,333,@,444,@,555,@,666@]@.";;
- : string
=
"111,222,333,444,555,666\n"

Why doesn't sprintf exhibit the same behaviour as printf?
Trying with fprintf…

# fprintf str_formatter "@[<hov0>111,@,222,@,333,@,444,@,555,@,666@]@.";;
- : unit
= ()
# flush_str_formatter ();;
- : string
=
"111,222,333,444,555,666\n"

-- 
Matthieu Dubuget


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [Caml-list] I never succeeded in using Format
  2014-03-06 16:34 [Caml-list] I never succeeded in using Format Matthieu Dubuget
@ 2014-03-06 16:46 ` Jeremy Yallop
  2014-03-06 16:47 ` Benoit Vaugon
  1 sibling, 0 replies; 12+ messages in thread
From: Jeremy Yallop @ 2014-03-06 16:46 UTC (permalink / raw)
  To: Matthieu Dubuget; +Cc: caml-list

On 6 March 2014 16:34, Matthieu Dubuget <matthieu.dubuget@gmail.com> wrote:
> Why doesn't sprintf exhibit the same behaviour as printf?

The set_margin function only affects std_formatter:

   https://github.com/ocaml/ocaml/blob/8ba031a/stdlib/format.ml#L1027

You need to use pp_set_margin for other formatters.

Jeremy.

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [Caml-list] I never succeeded in using Format
  2014-03-06 16:34 [Caml-list] I never succeeded in using Format Matthieu Dubuget
  2014-03-06 16:46 ` Jeremy Yallop
@ 2014-03-06 16:47 ` Benoit Vaugon
  2014-03-06 17:02   ` Matthieu Dubuget
  1 sibling, 1 reply; 12+ messages in thread
From: Benoit Vaugon @ 2014-03-06 16:47 UTC (permalink / raw)
  To: Matthieu Dubuget; +Cc: caml-list

[-- Attachment #1: Type: text/plain, Size: 1916 bytes --]

Hi,

The set_margin function configure the std_formatter, ie the formatter of
the standard output (the one used by printf). To change the margin when
printing in a buffer, you can run something like this :

# open Format;;
# let buf = Buffer.create 16;;
val buf : Buffer.t = <abstr>
# let formatter = formatter_of_buffer buf;;
val formatter : Format.formatter = <abstr>
# pp_set_margin formatter 9;;
- : unit = ()
# fprintf formatter "@[<hov0>111,@,222,@,333,@,444,@,555,@,666@]@.";;
- : unit = ()
# Buffer.contents buf;;
- : string = "111,222,\n333,444,\n555,666\n"

Best regards,
Benoît Vaugon.



2014-03-06 17:34 GMT+01:00 Matthieu Dubuget <matthieu.dubuget@gmail.com>:

> Is the following behaviour expected, or a misunderstanding of mine?
>
> In short, I'd like to use the Format module to prepare an
> output inside a Buffer.t. But a basic <hov> box does not
> break lines as I would expect, while printf does.
>
> OCaml version 4.01.0
>
> # open Format;;
> # printf "@[<hov0>111,@,222,@,333,@,444,@,555,@,666@]@.";;
> 111,222,333,444,555,666
> - : unit = ()
> # set_margin 9;;
> - : unit
> = ()
> # printf "@[<hov0>111,@,222,@,333,@,444,@,555,@,666@]@.";;
> 111,222,
> 333,444,
> 555,666
> - : unit
> = ()
> # sprintf "@[<hov0>111,@,222,@,333,@,444,@,555,@,666@]@.";;
> - : string
> =
> "111,222,333,444,555,666\n"
>
> Why doesn't sprintf exhibit the same behaviour as printf?
> Trying with fprintf...
>
> # fprintf str_formatter "@[<hov0>111,@,222,@,333,@,444,@,555,@,666@]@.";;
> - : unit
> = ()
> # flush_str_formatter ();;
> - : string
> =
> "111,222,333,444,555,666\n"
>
> --
> Matthieu Dubuget
>
>
> --
> Caml-list mailing list.  Subscription management and archives:
> https://sympa.inria.fr/sympa/arc/caml-list
> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
> Bug reports: http://caml.inria.fr/bin/caml-bugs
>

[-- Attachment #2: Type: text/html, Size: 2966 bytes --]

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [Caml-list] I never succeeded in using Format
  2014-03-06 16:47 ` Benoit Vaugon
@ 2014-03-06 17:02   ` Matthieu Dubuget
  2014-03-06 17:06     ` David Sheets
  0 siblings, 1 reply; 12+ messages in thread
From: Matthieu Dubuget @ 2014-03-06 17:02 UTC (permalink / raw)
  To: caml-list

Oh! Thanks for your answers…

I had checked in the documentation if set_margin was not only for
std_formatter, but did not find any warning…

And I overlooked pp_set_margin…

OK. I now could propose a small improvement of the documentation.

Is the documentation in a public repository?

Salutations

-- 
Matthieu Dubuget


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [Caml-list] I never succeeded in using Format
  2014-03-06 17:02   ` Matthieu Dubuget
@ 2014-03-06 17:06     ` David Sheets
  2014-03-06 17:09       ` Matthieu Dubuget
  0 siblings, 1 reply; 12+ messages in thread
From: David Sheets @ 2014-03-06 17:06 UTC (permalink / raw)
  To: Matthieu Dubuget; +Cc: caml-list

On Thu, Mar 6, 2014 at 5:02 PM, Matthieu Dubuget
<matthieu.dubuget@gmail.com> wrote:
> Oh! Thanks for your answers...
>
> I had checked in the documentation if set_margin was not only for
> std_formatter, but did not find any warning...
>
> And I overlooked pp_set_margin...
>
> OK. I now could propose a small improvement of the documentation.
>
> Is the documentation in a public repository?

<https://github.com/ocaml/ocaml/blob/trunk/stdlib/format.mli>

> Salutations
>
> --
> Matthieu Dubuget
>
>
> --
> Caml-list mailing list.  Subscription management and archives:
> https://sympa.inria.fr/sympa/arc/caml-list
> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
> Bug reports: http://caml.inria.fr/bin/caml-bugs

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [Caml-list] I never succeeded in using Format
  2014-03-06 17:06     ` David Sheets
@ 2014-03-06 17:09       ` Matthieu Dubuget
  2014-03-06 19:08         ` Martin Jambon
  0 siblings, 1 reply; 12+ messages in thread
From: Matthieu Dubuget @ 2014-03-06 17:09 UTC (permalink / raw)
  Cc: caml-list

Thanks again!

I never realized that the documentation was generated from the .mli.

Maybe, it is the time to go home…


-- 
Matthieu Dubuget


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [Caml-list] I never succeeded in using Format
  2014-03-06 17:09       ` Matthieu Dubuget
@ 2014-03-06 19:08         ` Martin Jambon
  2014-03-07  7:20           ` Raphaël Proust
  0 siblings, 1 reply; 12+ messages in thread
From: Martin Jambon @ 2014-03-06 19:08 UTC (permalink / raw)
  To: Matthieu Dubuget; +Cc: caml-list

Note that I made a library called easy-format that supposedly makes it 
easier to pretty-print code exactly the way you want:

project page:
  http://mjambon.com/easy-format.html

sample code + output:
  http://mjambon.com/easy_format_example.html


Martin

On Thu 06 Mar 2014 09:09:38 AM PST, Matthieu Dubuget wrote:
> Thanks again!
>
> I never realized that the documentation was generated from the .mli.
>
> Maybe, it is the time to go home…
>
>



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [Caml-list] I never succeeded in using Format
  2014-03-06 19:08         ` Martin Jambon
@ 2014-03-07  7:20           ` Raphaël Proust
  2014-03-10  0:47             ` oleg
  0 siblings, 1 reply; 12+ messages in thread
From: Raphaël Proust @ 2014-03-07  7:20 UTC (permalink / raw)
  To: Martin Jambon; +Cc: Matthieu Dubuget, caml-list

On Thu, Mar 6, 2014 at 7:08 PM, Martin Jambon
<martin.jambon@ens-lyon.org> wrote:
> Note that I made a library called easy-format that supposedly makes it
> easier to pretty-print code exactly the way you want:
>
> project page:
>  http://mjambon.com/easy-format.html
>
> sample code + output:
>  http://mjambon.com/easy_format_example.html

Another alternative to format for pretty-printing code (or other things): PPrint

Release blog post (with some examples of use):
http://gallium.inria.fr/blog/first-release-of-pprint/
Documentation: http://gallium.inria.fr/~fpottier/pprint/doc/PPrint.html
Installation instruction: `opam install pprint`


Cheers,
-- 
______________
Raphaël Proust

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [Caml-list] I never succeeded in using Format
  2014-03-07  7:20           ` Raphaël Proust
@ 2014-03-10  0:47             ` oleg
  2014-03-10 11:28               ` Bob Atkey
  0 siblings, 1 reply; 12+ messages in thread
From: oleg @ 2014-03-10  0:47 UTC (permalink / raw)
  To: raphlalou; +Cc: caml-list, martin.jambon


> Another alternative to format for pretty-printing code (or other things): PPrint
>
> Release blog post (with some examples of use):
> http://gallium.inria.fr/blog/first-release-of-pprint/
> Documentation: http://gallium.inria.fr/~fpottier/pprint/doc/PPrint.html
> Installation instruction: `opam install pprint`

That formatter uses Wadler's Pretty-printer, which is not optimal. The
optimal one takes linear time in the size of the document (regardless
of the page width), and, for constant page width, formats documents of
any size in constant space. It is obviously incremental and has
bounded latency. There are several optimal formatters. The recent one
was based on simple generators, described in
        http://okmij.org/ftp/continuations/PPYield/index.html#pp

Curiously, a Clojure programmer has read our paper and re-wrote the
algorithm in Clojure -- without any help from us. It seems he is very
satisfied with the results:
        https://github.com/brandonbloom/fipp
That web page has a few examples.



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [Caml-list] I never succeeded in using Format
  2014-03-10  0:47             ` oleg
@ 2014-03-10 11:28               ` Bob Atkey
  2014-03-11  9:32                 ` oleg
  0 siblings, 1 reply; 12+ messages in thread
From: Bob Atkey @ 2014-03-10 11:28 UTC (permalink / raw)
  To: oleg; +Cc: raphlalou, caml-list, martin.jambon

Hi Oleg,

Have you compared your implementation to Christian Lindig's 'Strictly Pretty'?:

   http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.34.2200

I think the runtime of his implementation is dependent on page width,
due to repeated use of the fits function to measure whether a group
fits within the current line. A simple optimisation is to precompute
this width, as (I think) you do. I did this in my simple
implementation of Lindig's idea:

   https://github.com/bobatkey/pretty-monospace/blob/master/lib/Pretty.ml

Neither of these implementations are incremental though; both require
the entire document to be present up front.

Bob



On 10 March 2014 00:47,  <oleg@okmij.org> wrote:
>
>> Another alternative to format for pretty-printing code (or other things): PPrint
>>
>> Release blog post (with some examples of use):
>> http://gallium.inria.fr/blog/first-release-of-pprint/
>> Documentation: http://gallium.inria.fr/~fpottier/pprint/doc/PPrint.html
>> Installation instruction: `opam install pprint`
>
> That formatter uses Wadler's Pretty-printer, which is not optimal. The
> optimal one takes linear time in the size of the document (regardless
> of the page width), and, for constant page width, formats documents of
> any size in constant space. It is obviously incremental and has
> bounded latency. There are several optimal formatters. The recent one
> was based on simple generators, described in
>         http://okmij.org/ftp/continuations/PPYield/index.html#pp
>
> Curiously, a Clojure programmer has read our paper and re-wrote the
> algorithm in Clojure -- without any help from us. It seems he is very
> satisfied with the results:
>         https://github.com/brandonbloom/fipp
> That web page has a few examples.
>
>
>
> --
> Caml-list mailing list.  Subscription management and archives:
> https://sympa.inria.fr/sympa/arc/caml-list
> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
> Bug reports: http://caml.inria.fr/bin/caml-bugs

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [Caml-list] I never succeeded in using Format
  2014-03-10 11:28               ` Bob Atkey
@ 2014-03-11  9:32                 ` oleg
  2014-03-14 10:21                   ` Francois Pottier
  0 siblings, 1 reply; 12+ messages in thread
From: oleg @ 2014-03-11  9:32 UTC (permalink / raw)
  To: bob.atkey; +Cc: caml-list


> Have you compared your implementation to Christian Lindig's 'Strictly Pretty'?:
>    http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.34.2200
>
> ... 
> A simple optimisation is to precompute this width, as (I think) you
> do. I did this in my simple implementation of Lindig's idea:
>
>    https://github.com/bobatkey/pretty-monospace/blob/master/lib/Pretty.ml
>
> Neither of these implementations are incremental though; both require
> the entire document to be present up front.

Thank you for the reference! I should compare with his and your
implementations.

Our pretty-printer is designed from the outset to be incremental. It
operates on a stream of tokens: text-string, newline, begin-group,
end-group.  It is literally a functional composition of four stream
transformers which annotate the stream tokens and then format them,
outputting chunks of the final text. The formatting is simple if the
begin-group token is annotated with the width of the corresponding
group. The key idea is that we need to know this width only up to the
point: if it exceeds the page width, we don't need to know by how
much. So, computing this annotation requires only a bounded
look-ahead. It is crucial for the performance to use a sequence data
structure with the amortized constant-time addition and removal on
both ends. Standard libraries of Haskell and Clojure luckily provide
such a data structure.



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [Caml-list] I never succeeded in using Format
  2014-03-11  9:32                 ` oleg
@ 2014-03-14 10:21                   ` Francois Pottier
  0 siblings, 0 replies; 12+ messages in thread
From: Francois Pottier @ 2014-03-14 10:21 UTC (permalink / raw)
  To: oleg; +Cc: bob.atkey, caml-list


Dear all,

Interesting discussion, which prompted me to come out of my retreat and
publish a new implementation of PPrint, available now :-)

Oleg is right: the now-old PPrint implementation uses backtracking and its
time complexity is dependent on the window width.

Oleg's message caused me to think, and I realized that I had missed a major
opportunity for simplification and optimization, which in fact was shortly
thereafter mentioned by Bob in his reply to Oleg's message. The idea is
simple. The PPrint API requires the document to be constructed in an eager,
bottom-up manner. (One reason for this decision was syntax: I did not want the
user to have to write "lazy" everywhere, and I did not want to impose the use
of a syntax extension.) So, we are paying a high cost in space (linear space
overhead), but in return, it is easy to compute the required width of every
(sub-)document as it is constructed. This in turn means that the rendering
process can be performed in linear time, without dependency on the window
width, without any backtracking or buffering.

I have implemented this idea in the new version of PPrint and compared it with
the old version. In short, the results are as follows, for a set of
randomly-generated documents:

  - the construction of the document is roughly just as fast as it was
    (but documents occupy slightly more space in memory)

  - rendering is faster than before, between 2x and 3x faster

  - the code is much simpler than before (this is the key benefit)

  - two features are lost (namely, the primitive operators [nesting] and
    [column], which were used to get access to the engine's state during
    rendering; they are no longer supported because they prevent the width
    pre-computation).

I should point out that rendering is now between 10x and 20x faster than the
construction of the document, which (I believe) means that the current
implementation is essentially unbeatable in terms of throughput. So, in my
view, the bottom line is, if one is willing to live with linear space
overhead, then this approach is preferable for its simplicity and efficiency;
if one must work in constant space, then Oleg's approach is preferable.

The new release of PPrint is available here:

  http://gallium.inria.fr/~fpottier/pprint/pprint.tar.gz

and should reach opam pretty soon ("opam install pprint").

Best regards,

-- 
François Pottier
Francois.Pottier@inria.fr
http://gallium.inria.fr/~fpottier/

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2014-03-14 10:21 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-03-06 16:34 [Caml-list] I never succeeded in using Format Matthieu Dubuget
2014-03-06 16:46 ` Jeremy Yallop
2014-03-06 16:47 ` Benoit Vaugon
2014-03-06 17:02   ` Matthieu Dubuget
2014-03-06 17:06     ` David Sheets
2014-03-06 17:09       ` Matthieu Dubuget
2014-03-06 19:08         ` Martin Jambon
2014-03-07  7:20           ` Raphaël Proust
2014-03-10  0:47             ` oleg
2014-03-10 11:28               ` Bob Atkey
2014-03-11  9:32                 ` oleg
2014-03-14 10:21                   ` Francois Pottier

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).