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=AWL autolearn=disabled version=3.1.3 Received: from discorde.inria.fr (discorde.inria.fr [192.93.2.38]) by yquem.inria.fr (Postfix) with ESMTP id 82714BC6B for ; Wed, 27 Jun 2007 14:20:23 +0200 (CEST) Received: from ptb-relay03.plus.net (ptb-relay03.plus.net [212.159.14.214]) by discorde.inria.fr (8.13.6/8.13.6) with ESMTP id l5RCKMkE010061 (version=TLSv1/SSLv3 cipher=AES256-SHA bits=256 verify=NO) for ; Wed, 27 Jun 2007 14:20:23 +0200 Received: from [80.229.56.224] (helo=beast.local) by ptb-relay03.plus.net with esmtp (Exim) id 1I3WVR-0002kv-Uc for caml-list@yquem.inria.fr; Wed, 27 Jun 2007 13:20:22 +0100 From: Jon Harrop Organization: Flying Frog Consultancy Ltd. To: caml-list@yquem.inria.fr Subject: The Implicit Accumulator: a design pattern using optional arguments Date: Wed, 27 Jun 2007 13:14:34 +0100 User-Agent: KMail/1.9.7 MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline Message-Id: <200706271314.35134.jon@ffconsultancy.com> X-Miltered: at discorde with ID 46825606.000 by Joe's j-chkmail (http://j-chkmail . ensmp . fr)! X-Spam: no; 0.00; ocaml:01 val:01 val:01 ocaml:01 solver:01 hen:98 frog:98 char:01 rec:01 rec:01 clearer:01 functions:01 functions:01 accu:02 accu:02 I can't find the thread where we were talking about design patterns recently but I'd like to note a design pattern that works nicely in OCaml. I'll call it "The Implicit Accumulator". ML programmers often use nested auxiliary functions or separate functions to handle base cases. For example, writing rev in terms of rev_append: # let rec rev_append l1 l2 = match l1 with | [] -> l2 | a :: l -> rev_append l (a :: l2);; val rev_append : 'a list -> 'a list -> 'a list = # let rev l = rev_append l [];; val rev : 'a list -> 'a list = Provided performance is unimportant, you can make the accumulator implicit in OCaml by specifying the default value in an optional argument instead of having a separate function: # let rec rev ?(back=[]) = function | [] -> back | h::t -> rev ~back:(h::back) t;; val rev : ?back:'a list -> 'a list -> 'a list = When you don't want the auxiliary (rev_append) function, I think this style results in shorter and clearer code. I used it in the "search" function of my Sudoku solver, for example: let rec search ?(x=0) ?(y=0) f accu = match x, y with 9, y -> search ~x:0 ~y:(y+1) f accu (* Next row *) | 0, 9 -> f accu (* Found a solution *) | x, y -> if m.(y).[x] <> '0' then search ~x:(x+1) ~y f accu else fold (fun accu n -> let n = Char.chr (n + 48) in if invalid x y n then accu else (m.(y).[x] <- n; let accu = search ~x:(x+1) ~y f accu in m.(y).[x] <- '0'; accu)) accu 1 10 and it crops up quite a lot in addition to all of the "conventional" uses of optional arguments. -- Dr Jon D Harrop, Flying Frog Consultancy Ltd. The OCaml Journal http://www.ffconsultancy.com/products/ocaml_journal/?e