caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
From: Bill Wood <william.wood3@comcast.net>
To: caml-list@yquem.inria.fr
Subject: Re: Ant:  Re: [Caml-list] Avoiding shared data
Date: Sat, 01 Oct 2005 00:46:39 -0500	[thread overview]
Message-ID: <1128145599.23400.55.camel@localhost> (raw)
In-Reply-To: <200509301707.01281.pal_engstad@naughtydog.com>

   . . .
> I've always thought that this was a really bad argument from the ML camp. The 
> logic of complicated control-paths is very easily made a zillion times worse 
> by writing in a tail-recursive style. It is *not* a good programming practice 
> to make hard-to-read code!
> 
> I encourage people to read the paper by Olin Shivers: "The Anatomy of a Loop - 
> A story of scope and control", which was presented at ICFP 2005, and can be 
> found at http://www.cc.gatech.edu/~shivers/papers/loop.pdf.
> 
> The author argues that "Writing loops with tail-recursive function calls is 
> the equivalent of writing them with goto’s." and gives an example that I've 
> rewritten from Scheme-ish into OCaml-ish:
> 
> let myfunc l =
>   let rec loop rest result =
>     match rest with 
>       | [] -> List.rev result
>       | x::xs -> 
> 	  if xpred x then
> 	    let y = verbose_code_using_x x in
> 	      if ypred y then 
> 		let z = verbose_code_using_y y in
> 		  loop xs (z_expression :: result)
> 	      else
> 		loop xs result
> 	  else
> 	    loop xs result
>   in
>     loop l [] 
> ;;
> 
> Obviously, one would like to refactor this into HOF, but in this situation it 
> is hard to see how one should do it. The author instead proposes to use loops 
> in a monadic style, which I've again rewritten:
> 
> let myfunc l =
>    loop [ for x in l
> 	; when xpred x 
> 	;   let y = verbose_code_using_x x
> 	;   when ypred y
> 	;     let z = verbose_code_using_y y
> 	;     save z
> 	]
> 
> The point being (syntax aside) that this code is much more readible, easier to 
> change and easier to verify than the code given above. [Of course, Haskell 
> has the really cool list-comprehension syntax that alleviates some of ML's 
> problems, but still.]

I about half agree with Mr. Engstad's observation.  I have often used
the fact that the accumulator passed around in tail-recursive functions
acts like a state (some people call these *state threads*), and I've
used techniques like pushing Dijkstra's weakest-precondition predicate
transformers over accumulators to reason about tail-recursive functional
code almost as if it were imperative (the only difference with Mr.
Shivers is that my programming is goto-less :-).

However, the example is a little unfortunate in that transforming it to
an arguably cleaner HOF form is fairly easy.  If we first define
function composition as an operator (shouldn't this be an OCaml
Pervasive?), say

  let ($@) fyz fxy x = fyz (fxy x);;

then the tail-recursive version of myfunc transforms into my_hof_func:

   let my_hof_func l =
     let fumble =
       let save = rev $@ (fold_left (fun la i -> i :: la) []) in
         save $@
	   (map verbose_code_using_y) $@
	     (filter ypred) $@
	       (map verbose_code_using_x) $@
	         (filter xpred)
   in fumble l;;

where packaging and return of the result has been encapsulated in the
local function 'save' (I'm also assuming z_expression was supposed to be
z).

A minor problem is that the textual order of the predicates and
functions is reversed.  Even this can be handled by a sleazy trick --
reverse the order of the operands to the compose operator like so:

   let ($@) fxy fyz x = fyz (fxy x);;

We can then rewrite my_hof_func as

   let my_hof_func l =
     let fumble =
       let save = (fold_left (fun la i -> i :: la) []) $@ rev in
         (filter xpred)             $@
         (map verbose_code_using_x) $@
         (filter ypred)             $@
         (map verbose_code_using_y) $@
         save
   in fumble l;;

The actions/functions are read in the order they are performed/applied,
and trivial reformatting even makes it look sorta like imperative code.

A very similar transformation could be done on the "Scheme-ish"
original, where a variable-arity form (compose f1 ... fn) is used to
equally good effect.

I think the ease-of-reading issue can now be revisited on a slightly
more even playing field.  The transformed, HOF, code is a couple of
lines longer, but the meaning is fairly transparent because native OCaml
facilities are used throughout.  The monadic form above is a trifle
shorter, but has the liability that the new syntax has complex semantics
-- what *exactly* is going on with "when" and "save"?.  I note also that
the monadic form looks very similar to the infamous Common Lisp "loop"
facility (the one towards the back of The Book, with all the keywords).
Many lispers love it, and many loathe it.

Does anybody know if MLers have looked at either the Series or the
Generators-and-Gatherers described in Appendices A and B of Common Lisp
the Language, 2nd ed.?  Some of the ideas there look interesting.

Interesting topic,

 -- Bill Wood
    bill.wood@acm.org



  reply	other threads:[~2005-10-01  5:46 UTC|newest]

Thread overview: 44+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2005-09-25 21:32 Martin Chabr
2005-09-26  0:23 ` [Caml-list] " Bill Wood
2005-09-26  7:57 ` Claudio Sacerdoti Coen
2005-09-26  8:17 ` William Lovas
2005-09-26 21:07   ` Ant: " Martin Chabr
2005-09-26 22:08     ` Jon Harrop
2005-09-30 22:57     ` Oliver Bandel
2005-10-01  0:07       ` Pal-Kristian Engstad
2005-10-01  5:46         ` Bill Wood [this message]
2005-10-01  8:27         ` Wolfgang Lux
2005-10-01 18:02           ` Wolfgang Lux
2005-10-01 21:50           ` Ant: " Martin Chabr
2005-10-01 12:34         ` Oliver Bandel
2005-10-01 13:58           ` Bill Wood
2005-10-01 21:05         ` Ant: " Martin Chabr
2005-10-03  0:41           ` skaller
2005-10-03  1:13             ` Seth J. Fogarty
2005-10-03 13:09             ` Thomas Fischbacher
2005-10-03 14:57               ` skaller
2005-10-03 20:03               ` Ant: " Martin Chabr
2005-10-03 20:25                 ` Thomas Fischbacher
2005-10-03 21:08                 ` Jon Harrop
2005-10-04 18:06                   ` Ant: " Martin Chabr
2005-10-04 18:32                     ` Jon Harrop
2005-10-04  2:53                 ` skaller
2005-10-04 16:15                   ` Brian Hurt
2005-10-04 16:47                     ` FP/IP and performance (in general) and Patterns... (Re: [Caml-list] Avoiding shared data) Oliver Bandel
2005-10-04 22:38                       ` Michael Wohlwend
2005-10-05  0:31                         ` Jon Harrop
2005-10-04 22:39                       ` Christopher A. Watford
2005-10-04 23:14                         ` Jon Harrop
2005-10-05 12:10                         ` Oliver Bandel
2005-10-05 13:08                           ` Jon Harrop
2005-10-05 15:28                           ` skaller
2005-10-05 20:52                           ` Ant: " Martin Chabr
2005-10-05 23:21                             ` Markus Mottl
2005-10-06 16:54                               ` brogoff
2005-10-05  0:45                       ` Brian Hurt
2005-10-04 18:09                   ` Ant: Re: Ant: Re: Ant: Re: Ant: Re: [Caml-list] Avoiding shared data Martin Chabr
2005-10-05  8:42                     ` skaller
2005-10-05 11:14               ` Andrej Bauer
2005-10-01 21:36       ` Ant: Re: Ant: " Martin Chabr
2005-10-03 11:51         ` getting used to FP-programming (Re: Ant: Re: Ant: Re: [Caml-list] Avoiding shared data) Oliver Bandel
     [not found] <Pine.LNX.4.63.0509251653340.9226@localhost.localdomain>
2005-09-26 21:29 ` Ant: Re: [Caml-list] Avoiding shared data Martin Chabr

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=1128145599.23400.55.camel@localhost \
    --to=william.wood3@comcast.net \
    --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).