From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.1.3 (2006-06-01) on yquem.inria.fr X-Spam-Level: X-Spam-Status: No, score=0.0 required=5.0 tests=none autolearn=disabled version=3.1.3 X-Original-To: caml-list@yquem.inria.fr Delivered-To: caml-list@yquem.inria.fr Received: from mail1-relais-roc.national.inria.fr (mail1-relais-roc.national.inria.fr [192.134.164.82]) by yquem.inria.fr (Postfix) with ESMTP id 5B5C9BBAF for ; Sun, 6 Jul 2008 23:11:05 +0200 (CEST) X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: AvMDAFbRcEjUnw7VZWdsb2JhbACCOpAiEgIeA5or X-IronPort-AV: E=Sophos;i="4.30,311,1212357600"; d="scan'208";a="14818223" Received: from ptb-relay02.plus.net ([212.159.14.213]) by mail1-smtp-roc.national.inria.fr with ESMTP/TLS/AES256-SHA; 06 Jul 2008 23:11:05 +0200 Received: from [90.192.139.19] (helo=beast.local) by ptb-relay02.plus.net with esmtpa (Exim) id 1KFbVg-0007Dz-3X for caml-list@yquem.inria.fr; Sun, 06 Jul 2008 22:11:04 +0100 From: Jon Harrop Organization: Flying Frog Consultancy Ltd. To: caml-list@yquem.inria.fr Subject: Re: [Caml-list] Newbie question: OCaml equivalent of Haskell's show? Date: Sun, 6 Jul 2008 22:09:11 +0100 User-Agent: KMail/1.9.9 References: <3be64c030807060833y155230a2gaeaf0e531827ddb3@mail.gmail.com> In-Reply-To: <3be64c030807060833y155230a2gaeaf0e531827ddb3@mail.gmail.com> MIME-Version: 1.0 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 7bit Content-Disposition: inline Message-Id: <200807062209.11682.jon@ffconsultancy.com> X-Plusnet-Relay: b7070fb6ba3822e15876ae9a8f486f57 X-Spam: no; 0.00; ocaml:01 haskell's:01 haskell:01 ocaml:01 runtime:01 run-time:01 recursive:01 mutable:01 haskell:01 fprintf:01 fprintf:01 val:01 notation:01 val:01 ocaml's:01 On Sunday 06 July 2008 16:33:35 Antony Courtney wrote: > I'm an experienced Haskell hacker trying OCaml for the first time. > > One thing I am desperately searching for but have been unable to find > is some direct runtime access to the string representation of > arbitrary OCaml values. OCaml has no run-time type information, no structural pretty printers in compiled code and no type classes to help you implement your own in source code. > I have written a little option pricer that constructs a > float option array array > in a function. I've got a little buglet in my function so I'd like to > print the intermediate states of this value from inside the function. > How do I do that, short of writing my own recursive pretty printer / > formatter? You basically have two choices: . Run in the top-level and get the value you require as the result of evaluating an expression (e.g. by raising an exception, or by setting a mutable). . Write your own print function(s) and call them. The benefit of the latter is, of course, that it works from compiled code. > An OCaml form of the Haskell Show type class would be great, IMHO, type classes are great for some things but pretty printing is not one of them. Start with a function to print a list with an arbitrary separator: # open Format;; # let rec fprintfs sep f ff = function | [] -> () | [h] -> fprintf ff "%a" f h | h::t -> fprintf ff "%a%a%a" f h sep () (fprintfs sep f) t;; val fprintfs : (Format.formatter -> unit -> unit) -> (Format.formatter -> 'a -> unit) -> Format.formatter -> 'a list -> unit = For example, we can now write a function to pretty print a list in Mathematica notation: # let fprintf_mma ff list = let sep ff () = fprintf ff ",@ " in let int ff = fprintf ff "%d" in fprintf ff "{@[%a@]}" (fprintfs sep int) list;; val fprintf_mma : Format.formatter -> int list -> unit = # fprintf std_formatter "%a\n" fprintf_mma (Array.to_list(Array.init 100 (fun n -> n)));; {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99} - : unit = () Note the automatically-aligned wrapping thanks to OCaml's pretty printing "Format" module and the use of "@[", "@ " and "@]" in my code. This also works from compiled code and is an excellent way to print indented source code (e.g. when generating other languages). To pretty print a generic array: # let fprintf_array f ff array = let sep ff () = fprintf ff ";@ " in fprintf ff "[|@[%a@]|]" (fprintfs sep f) (Array.to_list array);; val fprintf_array : (Format.formatter -> 'a -> unit) -> Format.formatter -> 'a array -> unit = To print an option: # let rec fprintf_opt f ff = function | None -> fprintf ff "None" | Some x -> fprintf ff "Some %a" f x;; val fprintf_opt : (Format.formatter -> 'a -> unit) -> Format.formatter -> 'a option -> unit = Now you can print your array of arrays of float options: # let print ff xss = let float ff = fprintf ff "%g" in fprintf_array (fprintf_array (fprintf_opt float)) ff xss;; val print : Format.formatter -> float option array array -> unit = # fprintf std_formatter "%a\n" print [|[|Some 3.; None; None|]; [|None; Some 5.; None|]; [|Some 1.|]|];; [|[|Some 3; None; None|]; [|None; Some 5; None|]; [|Some 1|]|] - : unit = () > but a hack to provide programmatic access to the polymorphic > pretty printer that obviously already exists in the OCaml toplevel > would be fine. In addition to Richard's suggestions, you might look at generating OCaml expressions using camlp4 and then printing those instead. Just an idea (I've never tried it). > I've scoured the standard library docs, manual, tutorials and a few > books, looked at the FAQ and am amazed that I haven't found the answer > to this. I am hopefully just missing something obvious; would be > grateful if someone could point me towards the answer! Surprisingly, structural printing is something that OCamlers rarely do. As part of my evolution as a programmer I had migrated everything from C++ and Mathematica to OCaml a few years ago but I am actually about to move a little parsing-related project from OCaml to F# simply because its built-in pretty printers make life so much easier. Anyway, I shall write an OCaml Journal article about OCaml's wonderful "Format" module. Incidentally, the OCaml Journal has recovered from a lull in Q1 and has really started to pick up now. So I still think there is plenty of opportunity for budding authors to write OCaml books! -- Dr Jon D Harrop, Flying Frog Consultancy Ltd. http://www.ffconsultancy.com/products/?e