From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: <5764c029b688c1c0d24a2e97cd764f@gmail.com> Received: from mail2-relais-roc.national.inria.fr (mail2-relais-roc.national.inria.fr [192.134.164.83]) by sympa.inria.fr (Postfix) with ESMTPS id 1ED2C7EE6B for ; Fri, 29 Nov 2013 10:32:00 +0100 (CET) Received-SPF: None (mail2-smtp-roc.national.inria.fr: no sender authenticity information available from domain of 5764c029b688c1c0d24a2e97cd764f@gmail.com) identity=pra; client-ip=209.85.214.41; receiver=mail2-smtp-roc.national.inria.fr; envelope-from="5764c029b688c1c0d24a2e97cd764f@gmail.com"; x-sender="5764c029b688c1c0d24a2e97cd764f@gmail.com"; x-conformance=sidf_compatible Received-SPF: Pass (mail2-smtp-roc.national.inria.fr: domain of 5764c029b688c1c0d24a2e97cd764f@gmail.com designates 209.85.214.41 as permitted sender) identity=mailfrom; client-ip=209.85.214.41; receiver=mail2-smtp-roc.national.inria.fr; envelope-from="5764c029b688c1c0d24a2e97cd764f@gmail.com"; x-sender="5764c029b688c1c0d24a2e97cd764f@gmail.com"; x-conformance=sidf_compatible; x-record-type="v=spf1" Received-SPF: None (mail2-smtp-roc.national.inria.fr: no sender authenticity information available from domain of postmaster@mail-bk0-f41.google.com) identity=helo; client-ip=209.85.214.41; receiver=mail2-smtp-roc.national.inria.fr; envelope-from="5764c029b688c1c0d24a2e97cd764f@gmail.com"; x-sender="postmaster@mail-bk0-f41.google.com"; x-conformance=sidf_compatible X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: Ao4DAPJdmFLRVdYpm2dsb2JhbABZghsEukyBHhYOAQEBAQEGCwsJFCiCJQEBBAEnGQEbHAEBAwwGBQsNCRYPCQMCAQIBEREBBQEcEwEFAgKHagEDCQYEAaNFjFmDCYQnChknDWSHHhEBBQyOFDUzB4QzA5gUhkWJYUGEVQ X-IPAS-Result: Ao4DAPJdmFLRVdYpm2dsb2JhbABZghsEukyBHhYOAQEBAQEGCwsJFCiCJQEBBAEnGQEbHAEBAwwGBQsNCRYPCQMCAQIBEREBBQEcEwEFAgKHagEDCQYEAaNFjFmDCYQnChknDWSHHhEBBQyOFDUzB4QzA5gUhkWJYUGEVQ X-IronPort-AV: E=Sophos;i="4.93,796,1378850400"; d="scan'208";a="46047312" Received: from mail-bk0-f41.google.com ([209.85.214.41]) by mail2-smtp-roc.national.inria.fr with ESMTP/TLS/RC4-SHA; 29 Nov 2013 10:31:59 +0100 Received: by mail-bk0-f41.google.com with SMTP id v15so4191406bkz.14 for ; Fri, 29 Nov 2013 01:31:59 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=message-id:date:from:user-agent:mime-version:to:cc:subject :references:in-reply-to:content-type:content-transfer-encoding; bh=A4E52RDA2yzEw8j8sT5srHygXUnQ2eMmTSjnFHFNj48=; b=iDVxPlJIHq7OP8E/7FkQDET/GcZKRMfSNRC2DOdI6DfClYqL6ngxCx3tMAHai7odIN 8xWBTKxedxeDAKUrfxNIf+lZxEOoA9qwVMC8u5QM0g1tYyciB6Z9NElFbm8BnactmjZ8 z0UldUeeUsJP6EYXG8AZxwzdZJ3QKDrv/z3MnP4yGLo+9gQ0C3UfEaX6vJi9lELKm1Au FguQdibdAZnT12WtgxRFV/Xo5xJZkiP/zeoddnMQHJD11fnzzcFN32QKHwobbf24eJus E+1cAkwlniHZ3xYBI2q7ryGO7JVQNu9KVwb0wlHU0H4CB757VzH4U45vKniv+HadwPm2 qTWw== X-Received: by 10.205.40.137 with SMTP id tq9mr13913bkb.168.1385717519003; Fri, 29 Nov 2013 01:31:59 -0800 (PST) Received: from [172.27.6.192] ([213.106.240.92]) by mx.google.com with ESMTPSA id xm9sm6523309bkb.1.2013.11.29.01.31.58 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Fri, 29 Nov 2013 01:31:58 -0800 (PST) Message-ID: <52985F14.4090508@gmail.com> Date: Fri, 29 Nov 2013 09:32:04 +0000 From: Matej Kosik <5764c029b688c1c0d24a2e97cd764f@gmail.com> User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:17.0) Gecko/20131005 Icedove/17.0.9 MIME-Version: 1.0 To: oleg@okmij.org CC: caml-list@inria.fr, gabriel.scherer@gmail.com References: <20131128063044.55659.qmail@www1.g3.pair.com> In-Reply-To: <20131128063044.55659.qmail@www1.g3.pair.com> X-Enigmail-Version: 1.6 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit Subject: Re: [Caml-list] [batteries] ... how to create (format) directives On 28/11/13 06:30, oleg@okmij.org wrote: > > Enclosed is one example of a combinator library for formatting, in > plain OCaml (even Caml-lite, probably), with no extensions, GADTs, > type classes, etc. Here is a simple demo This is interesting. Thank you. > > let ex1 = let open PrintComp in > pr s"1" s"2" printf > > (* prints: 12 *) > > (* Look! No string concatenation operations! We separate operations > with mere white space (and often even it is not needed > *) > > let ex2 = let open PrintComp in > pr s"1" s"2" b"3" i 4 > sprintf > (* > val ex2 : string = "1234" > *) > > > (* The format is really typed *) > let ex3 = let open PrintComp in > pr s"1" s"2" i "x" b"3" i 4 > sprintf > (* > Characters 50-53: > pr s"1" s"2" i "x" b"3" i 4 > ^^^ > Error: This expression has type string but an expression was expected of type > int > *) > > > (* It is possible to avoid s" " below, so to insert interworld space > automatically > *) I do not understand what do you have in mind (above). (Sometimes spaces are desired, sometimes they are undesired. I do not see a general rule that could be embedded to `b' so that it could reliably decide in either way.) > > let ex4 = let open PrintComp in pr > b"mdx" s" " it "command" br > s"Perform a given " it "command" br > s"Section COMMANDS describes all the supported commands." > sprintf > > (* > val ex4 : string = > "mdx command\n\nPerform a given command\n\nSection COMMANDS describes all the supported commands." > *) > > (* The formatting sequence can be interrupted, e.g., > to bind some common subexpressions or to perform some computations > *) > > let ra = fun x f -> f x > > let ex5 = let open PrintComp in pr > b"mdx" s" " > (* interrupt the flow *) > begin let cmd st = ra st it "command" in > fun st -> ra st (* continue with the flow *) > cmd br > s"Perform a given " cmd br > s"Section COMMANDS describes all the supported commands." end > sprintf > > (* > val ex5 : string = > "mdx command\n\nPerform a given command\n\nSection COMMANDS describes all the supported commands." > *) > > > Here is the implementation, of a FORTH like language for formatting. > Polyvariadic functions are possible even in plain OCaml. > > module PrintComp = struct > (* Put this at the beginning *) > let pr k = k [] > > (* to format a string *) > let s = fun st (str:string) k -> k (str :: st) > > (* to format a string in bold *) > let b = fun st (str:string) k -> k ("" :: str :: "" :: st) > > (* to format a string in italics *) > let it = fun st (str:string) k -> k ("" :: str :: "" :: st) > > (* to format an integer *) > let i = fun st n k -> k (string_of_int n :: st) > > (* generate a line break *) > let br = fun st k -> k ("\n\n" :: st) > > (* To finally print as a string *) > let sprintf st = String.concat "" (List.rev st) > > (* To finally print on stdout *) > let printf st = List.iter print_string (List.rev st) > > (* To finally print on channel *) > (* similarly *) > end;; > >