caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
From: Jon Harrop <jon@ffconsultancy.com>
To: caml-list@yquem.inria.fr
Subject: Re: [Caml-list] The Implicit Accumulator: a design pattern using optional arguments
Date: Wed, 27 Jun 2007 19:17:55 +0100	[thread overview]
Message-ID: <200706271917.55344.jon@ffconsultancy.com> (raw)
In-Reply-To: <468293D4.3000100@functionality.de>

On Wednesday 27 June 2007 17:44:04 you wrote:
> Jon Harrop wrote:
> > This seems to be something that Lisp uses to allocate data structures on
> > the stack rather than the heap. Why would you want that?
>
> In order to avoid dynamic memory management and get dynamically scoped
> pre-allocated "implicit context" buffers to which I can refer as if they
> were ordinary variables.

Do you mean something like this:

let dt() =
  let start = ref (time()) in
  fun () ->
    let time' = time() in
    let dt = time' -. !start in
    start := time';
    dt

Call dt() to get a new delta timer, call the delta timer to get the time since 
it was last called:

# let dt1 = dt();;
val dt1 : unit -> float = <fun>
# let dt2 = dt();;
val dt2 : unit -> float = <fun>
# dt1();;
- : float = 4.66352200508117676
# dt2();;
- : float = 4.48727107048034668
# dt1();;
- : float = 3.36179709434509277
# dt2();;
- : float = 2.09420299530029297

You could call this a factory pattern.

> > let float_factorial =
> >   let m = ref [||] in
> >   fun n ->
> >     try (!m).(n) with _ ->
> >     let m' = Array.make (n + 1) 1. in
> >     for i=1 to n do
> >       m'.(i) <- float i *. m'.(i - 1)
> >     done;
> >     m := m';
> >     m'.(n);;
>
> Well, it avoids some of the computations in your example, which re-does
> all the array whenever it has to be extended.

On "float_factorial 1000000", my original implementation was >2x faster. If 
you call for slowly increasing arguments then you can do much better still by 
doubling the length of the array to amortize allocation:

let float_factorial3 =
  let n = ref 0 in
  let m = ref [||] in
  fun j ->
    if j <= !n then (!m).(j) else
      if j < Array.length !m then begin
	let m' = !m in
	for i = !n to j do
	  m'.(i) <- float i *. m'.(i - 1)
	done;
	m := m';
	m'.(j)
      end else begin
	n := j;
	let m' = Array.make (2 * j + 1) 1. in
	for i=1 to j do
	  m'.(i) <- float i *. m'.(i - 1)
	done;
	m := m';
	m'.(j)
      end

This is ~7x faster for 1 .. 20000.

> >>Other advanced optimization techniques that can be used for benefit
> >>in very specialized situations include (explicit) continuation coding:
> >>rather than returning a value (e.g. a tuple), you take as an argument
> >>a function to which you then pass on your return value(s). This is quite
> >>useful whenever "execution flow branches out into multiple paths that
> >>have to be taken",
> >
> > Are you referring to CPS?
>
> Yes, but not the call/cc implicit CPS, but explicitly passing around
> continuations.

Yes, that's very useful in OCaml.

> >>and may sometimes (though rarely) also be used for
> >>good as a poor man's VALUES/MULTIPLE-VALUE-BIND substitute.
> >
> > Weren't values and multiple-value-bind completely superceded by pattern
> > matching?
>
> No. :-) Pattern matching requires constructors, which cons.

Here is a pattern match without constructors:

  let x = 3

Here is a pattern match that doesn't cons:

  let f(x, y) = x + y in
  f 3 4

Here is a pattern match with constructors that doesn't cons:

  type t = A | B

  let f = function
    | A -> 0
    | B -> 1

What exactly are you having trouble implementing in OCaml? It sounds as if 
you're still trying to work around the inefficiencies of Lisp and the beauty 
of OCaml is that you don't have to. :-)

Incidentally, the ray tracer is a good demonstration of this. The performance 
of the Lisp implementations is crippled by very slow allocation and 
deallocation. Juho Snellman tried to circumvent this problem using 
multiple-value-bind in a macro:

(defmacro def ((name params &body body)
               (mname &rest mparams)
               (wname &rest wparams))
  `(progn
    (declaim (inline ,name ,wname))
    (defun ,name ,params
      (declare (type double-float ,@params))
      ,@body)
    (defmacro ,mname ,(mapcar #'car mparams)
      ,(loop with inner = (list name)
             with body = ``,',inner
             with all-names = nil
             for (form count) in (reverse mparams)
             for names = (loop repeat count collect (gensym))
             do
             (setf all-names (append all-names names))
             (setf body ``(multiple-value-bind ,',(reverse names)
                           ,,form ,,body))
             finally
             (setf (cdr inner) (reverse all-names))
             (return body)))
    (defun ,wname ,(mapcar #'car wparams)
      (,mname ,@(mapcar #'cadr wparams)))))

While this greatly improves the performance of the Lisp, it remains far slower 
than most other languages.

The equivalent optimization in OCaml is to pass multiple arguments in curried 
form, exploiting ocamlopt's big step semantics without losing the 
expressiveness of a functional style.

-- 
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
The OCaml Journal
http://www.ffconsultancy.com/products/ocaml_journal/?e


  reply	other threads:[~2007-06-27 18:23 UTC|newest]

Thread overview: 60+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-06-27 12:14 Jon Harrop
2007-06-27 13:18 ` [Caml-list] " Quôc Peyrot
2007-06-27 13:53   ` Jon Harrop
2007-06-27 14:18     ` Thomas Fischbacher
2007-06-27 15:09     ` Quôc Peyrot
2007-06-27 15:28     ` Mattias Engdegård
2007-06-27 15:38       ` Robert Fischer
2007-06-27 15:48         ` Mattias Engdegård
2007-06-27 16:01           ` Robert Fischer
2007-06-27 16:01           ` Mattias Engdegård
2007-06-27 18:06           ` Jon Harrop
2007-06-27 18:31             ` Brian Hurt
2007-06-27 19:56               ` skaller
2007-06-27 20:17               ` Jonathan Bryant
2007-06-27 22:57               ` Jon Harrop
2007-06-27 16:53     ` Hash-consing (was Re: [Caml-list] The Implicit Accumulator: a design pattern using optional arguments) Daniel Bünzli
2007-06-30  8:19     ` [Caml-list] The Implicit Accumulator: a design pattern using optional arguments Pierre Etchemaïté
2007-06-27 13:55   ` Thomas Fischbacher
2007-06-27 15:06     ` Quôc Peyrot
2007-06-27 15:53       ` Jon Harrop
2007-06-28 11:01         ` Thomas Fischbacher
2007-06-28 11:32           ` Jon Harrop
2007-06-28 11:42             ` Joel Reymont
2007-06-28 12:08               ` Jon Harrop
2007-06-28 13:10                 ` Quôc Peyrot
2007-06-28 13:35                   ` Thomas Fischbacher
2007-06-28 12:59             ` Thomas Fischbacher
2007-06-28 13:05               ` Jon Harrop
2007-06-28 13:33                 ` Thomas Fischbacher
2007-06-28 14:43                   ` Jon Harrop
2007-06-28 16:01                     ` Thomas Fischbacher
2007-06-28 17:53                       ` Jon Harrop
2007-06-27 16:39       ` Thomas Fischbacher
2007-06-27 19:26         ` Quôc Peyrot
2007-06-28 11:39           ` Thomas Fischbacher
2007-06-28 14:44             ` Jon Harrop
2007-06-28 16:03               ` Thomas Fischbacher
2007-06-28 17:20                 ` Dirk Thierbach
2007-06-28 22:12                   ` Thomas Fischbacher
2007-06-29  1:10                     ` Jon Harrop
2007-06-29 10:55                       ` Thomas Fischbacher
2007-06-29  6:12                     ` Dirk Thierbach
2007-06-27 17:16       ` Book about functional design patterns Gabriel Kerneis
2007-06-27 17:48         ` [Caml-list] " Jon Harrop
2007-06-27 19:33           ` Quôc Peyrot
2007-06-27 19:30         ` Quôc Peyrot
2007-06-27 19:48           ` Brian Hurt
2007-06-27 20:04             ` Quôc Peyrot
2007-06-27 20:35               ` Brian Hurt
2007-06-27 20:55                 ` Quôc Peyrot
2007-06-27 20:58                   ` Pal-Kristian Engstad
2007-06-27 21:18                     ` Quôc Peyrot
2007-06-27 21:18                       ` Pal-Kristian Engstad
2007-06-27 21:34                         ` Quôc Peyrot
2007-06-27 22:13                           ` Pal-Kristian Engstad
2007-06-27 15:18     ` [Caml-list] The Implicit Accumulator: a design pattern using optional arguments Jon Harrop
2007-06-27 16:44       ` Thomas Fischbacher
2007-06-27 18:17         ` Jon Harrop [this message]
2007-06-28 11:18           ` Thomas Fischbacher
2007-06-29 13:15     ` Bill Wood

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=200706271917.55344.jon@ffconsultancy.com \
    --to=jon@ffconsultancy.com \
    --cc=caml-list@yquem.inria.fr \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).