* Avoiding shared data
@ 2005-09-25 21:32 Martin Chabr
2005-09-26 0:23 ` [Caml-list] " Bill Wood
` (2 more replies)
0 siblings, 3 replies; 44+ messages in thread
From: Martin Chabr @ 2005-09-25 21:32 UTC (permalink / raw)
To: caml-list
Working with non-shared data structures in OCaml
Deep copy of OCaml structures, marshaling
================================================
Dear group members,
I need to process arrays of pairs of integers and
records ((int * record) array) in which all elements
must be updated individually, which means that
unshared data structures must be used. For arrays of
arrays I can produce unshared data by using the
library functions Array.copy and Array.append to
append the individual arrays into the embedding array.
It works, the low level arrays can be updated
individually. But I cannot use the same scheme to the
array of the (int * record) structures, because I do
not know how to copy these structures to dissolve the
sharing. I do not even know how to copy records. It
seems to me that this problem occurs always when I
want to produce an array of data with a fixed
structure automatically (rather than entering the
array [| ... |] by hand at the top level interpreter
using constants only). How can I produce completely
unshared structures?
What about marshaling and unmarshaling the data? This
should produce a deep copy of data objects. I have
tried it, it works, but it seems to me wasteful to
copy all the data twice only to get rid of the
sharing.
It would be great to know of a completely general (any
nested structures) and fast solution (without copying)
how to produce unshared data structures.
My environment is OCaml 3.08.02 for Windows on Win
2000, New Windows Interface v1.9RC4.
I am looking forward to you reply.
Regards,
Martin
Martin Chabr
Hochstrasse 28
8044 Zürich
Schweiz / Switzerland
Tel.P.: 01-261 17 24
___________________________________________________________
Was denken Sie über E-Mail? Wir hören auf Ihre Meinung: http://surveylink.yahoo.com/wix/p0379378.aspx
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: [Caml-list] Avoiding shared data
2005-09-25 21:32 Avoiding shared data Martin Chabr
@ 2005-09-26 0:23 ` Bill Wood
2005-09-26 7:57 ` Claudio Sacerdoti Coen
2005-09-26 8:17 ` William Lovas
2 siblings, 0 replies; 44+ messages in thread
From: Bill Wood @ 2005-09-26 0:23 UTC (permalink / raw)
To: Martin Chabr; +Cc: caml-list
. . .
> I need to process arrays of pairs of integers and
> records ((int * record) array) in which all elements
> must be updated individually, which means that
> unshared data structures must be used. For arrays of
> arrays I can produce unshared data by using the
> library functions Array.copy and Array.append to
> append the individual arrays into the embedding array.
> It works, the low level arrays can be updated
> individually. But I cannot use the same scheme to the
> array of the (int * record) structures, because I do
> not know how to copy these structures to dissolve the
> sharing. I do not even know how to copy records. It
> seems to me that this problem occurs always when I
> want to produce an array of data with a fixed
> structure automatically (rather than entering the
> array [| ... |] by hand at the top level interpreter
> using constants only). How can I produce completely
> unshared structures?
Funny you should mention it, I wrestled with this just this week. I'm
building a square, i.e. array of N elements, each of which is itself an
array of N cells, where a cell is a record with several fields. Here's
the way I did it:
1) I defined a function initial_cell : unit -> cell as
let initial_cell () =
let c = {field1 = val1; ...; fieldN = valN} in
c;;
2) I defined a function initial_row : int -> cell array as:
let initial_row n = Array.init n (fun i -> initial_cell ());;
3) I defined a function initial_square : int -> cell array array by:
let initial_square n = Array.init n (fun i -> initial_row ());;
I think the essential point is the Array.init function; since it expects
to set the i-th element of the new array to (f i) for unknown f, it
can't make an array that shares.
I hope this is of some help,
-- Bill Wood
bill.wood@acm.org
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: [Caml-list] Avoiding shared data
2005-09-25 21:32 Avoiding shared data 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
2 siblings, 0 replies; 44+ messages in thread
From: Claudio Sacerdoti Coen @ 2005-09-26 7:57 UTC (permalink / raw)
To: caml-list
> It would be great to know of a completely general (any
> nested structures) and fast solution (without copying)
> how to produce unshared data structures.
If you like to play with fire you can use this unsharing function
(that is not complete with respect to any data type, but it is sufficient
for my needs). Since it works on the run-time representation of data,
it can even unshare abstract data types.
exception CanNotUnshare;;
(* [unshare t] gives back a copy of t where all sharing has been removed *)
(* Physical equality becomes meaningful on unshared terms. Hashtables that *)
(* use physical equality can now be used to associate information to evey *)
(* node of the term. *)
val unshare: ?already_unshared:('a -> bool) -> 'a -> 'a
let unshare ?(already_unshared = function _ -> false) t =
let obj = Obj.repr t in
let rec aux obj =
if already_unshared (Obj.obj obj) then
obj
else
(if Obj.is_int obj then
obj
else if Obj.is_block obj then
begin
let tag = Obj.tag obj in
if tag < Obj.no_scan_tag then
begin
let size = Obj.size obj in
let new_obj = Obj.new_block 0 size in
Obj.set_tag new_obj tag ;
for i = 0 to size - 1 do
Obj.set_field new_obj i (aux (Obj.field obj i))
done ;
new_obj
end
else if tag = Obj.string_tag then
obj
else
raise CanNotUnshare
end
else
raise CanNotUnshare
)
in
Obj.obj (aux obj)
;;
--
----------------------------------------------------------------
Real name: Claudio Sacerdoti Coen
Doctor in Computer Science, University of Bologna
E-mail: sacerdot@cs.unibo.it
http://www.cs.unibo.it/~sacerdot
----------------------------------------------------------------
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: [Caml-list] Avoiding shared data
2005-09-25 21:32 Avoiding shared data 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
2 siblings, 1 reply; 44+ messages in thread
From: William Lovas @ 2005-09-26 8:17 UTC (permalink / raw)
To: caml-list; +Cc: Martin Chabr
Hi Martin,
On Sun, Sep 25, 2005 at 11:32:02PM +0200, Martin Chabr wrote:
> [...] But I cannot use the same scheme to the
> array of the (int * record) structures, because I do
> not know how to copy these structures to dissolve the
> sharing. I do not even know how to copy records.
> [...] How can I produce completely
> unshared structures?
Maybe i'm missing something, but if these are unmutable records, then why
do you need to concern yourself with any potential sharing? As long as the
array cells are not "shared" -- which they can't be, as far as i know --
you can update each one individually no matter what the sharing status of
their contents is.
If the records *are* mutable, then the suggestion to use Array.init should
be sufficient.
Hoping i might save you some work :)
William
^ permalink raw reply [flat|nested] 44+ messages in thread
* Ant: Re: [Caml-list] Avoiding shared data
2005-09-26 8:17 ` William Lovas
@ 2005-09-26 21:07 ` Martin Chabr
2005-09-26 22:08 ` Jon Harrop
2005-09-30 22:57 ` Oliver Bandel
0 siblings, 2 replies; 44+ messages in thread
From: Martin Chabr @ 2005-09-26 21:07 UTC (permalink / raw)
To: William Lovas; +Cc: caml-list
Hello William,
I am using a mutable record. I am programming this 90%
in the imperative (non-functional) style, so that I
can rewrite critical parts into Fortran easily.
Another reason is, I am an intermediate user and
finding out whether the recursion is a tail-one or not
is difficult for me. This is a kind of number
crunching problem and the data structures will be
huge.
Blessed are the creators of OCaml for the inclusion of
all imperative constructs.
Martin
--- William Lovas <wlovas@stwing.upenn.edu> schrieb:
> Hi Martin,
>
> On Sun, Sep 25, 2005 at 11:32:02PM +0200, Martin
> Chabr wrote:
> > [...] But I cannot use the same scheme to the
> > array of the (int * record) structures, because I
> do
> > not know how to copy these structures to dissolve
> the
> > sharing. I do not even know how to copy records.
> > [...] How can I produce completely
> > unshared structures?
>
> Maybe i'm missing something, but if these are
> unmutable records, then why
> do you need to concern yourself with any potential
> sharing? As long as the
> array cells are not "shared" -- which they can't be,
> as far as i know --
> you can update each one individually no matter what
> the sharing status of
> their contents is.
>
> If the records *are* mutable, then the suggestion to
> use Array.init should
> be sufficient.
>
> Hoping i might save you some work :)
>
> William
>
Martin Chabr
Hochstrasse 28
8044 Zürich
Schweiz / Switzerland
Tel.P.: 01-261 17 24
___________________________________________________________
Gesendet von Yahoo! Mail - Jetzt mit 1GB Speicher kostenlos - Hier anmelden: http://mail.yahoo.de
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Ant: Re: [Caml-list] Avoiding shared data
2005-09-26 21:07 ` Ant: " Martin Chabr
@ 2005-09-26 22:08 ` Jon Harrop
2005-09-30 22:57 ` Oliver Bandel
1 sibling, 0 replies; 44+ messages in thread
From: Jon Harrop @ 2005-09-26 22:08 UTC (permalink / raw)
To: caml-list
On Monday 26 September 2005 22:07, Martin Chabr wrote:
> I am using a mutable record. I am programming this 90%
> in the imperative (non-functional) style, so that I
> can rewrite critical parts into Fortran easily.
In case you haven't already - I'd advise you to write a simple working version
first.
--
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
Objective CAML for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Ant: Re: [Caml-list] Avoiding shared data
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 21:36 ` Ant: Re: Ant: " Martin Chabr
1 sibling, 2 replies; 44+ messages in thread
From: Oliver Bandel @ 2005-09-30 22:57 UTC (permalink / raw)
To: caml-list
On Mon, Sep 26, 2005 at 11:07:30PM +0200, Martin Chabr wrote:
> Hello William,
>
> I am using a mutable record. I am programming this 90%
> in the imperative (non-functional) style, so that I
> can rewrite critical parts into Fortran easily.
> Another reason is, I am an intermediate user and
> finding out whether the recursion is a tail-one or not
> is difficult for me.
When you 90% of your code are writing in imperative style
and do not go deeper into the functional/recursive
world, you will never be able to distinguish between
tail-rec and non-tail-rec style.
But: It is not really hard to find the distinction betwen
the two styles, but often the explanations are not made
well.
Sometimes it's only one or two words in an explanation about
tail-rec/non-tail-rec that must be substituted by other words,
and the distinction can be made visible very easy.
On the other hand: writing mor funtional/recursive code will
make you more used to to this...
Ciao,
Oliver
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Ant: Re: [Caml-list] Avoiding shared data
2005-09-30 22:57 ` Oliver Bandel
@ 2005-10-01 0:07 ` Pal-Kristian Engstad
2005-10-01 5:46 ` Bill Wood
` (3 more replies)
2005-10-01 21:36 ` Ant: Re: Ant: " Martin Chabr
1 sibling, 4 replies; 44+ messages in thread
From: Pal-Kristian Engstad @ 2005-10-01 0:07 UTC (permalink / raw)
To: caml-list; +Cc: Oliver Bandel
On Friday 30 September 2005 03:57 pm, Oliver Bandel wrote:
> On the other hand: writing mor funtional/recursive code will
> make you more used to to this...
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.]
Thanks,
PKE.
--
_
\`. Pål-Kristian Engstad, Lead Programmer,
\ `| Naughty Dog, Inc., 1601 Cloverfield Blvd, 6000 North,
__\ |`. Santa Monica, CA 90404, USA. (310) 633-9112.
/ /o mailto:engstad@naughtydog.com http://www.naughtydog.com
/ '~ mailto:mrengstad@yahoo.com http://www.engstad.com
/ ,' Hang-gliding Rulez!
~'
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Ant: Re: [Caml-list] Avoiding shared data
2005-10-01 0:07 ` Pal-Kristian Engstad
@ 2005-10-01 5:46 ` Bill Wood
2005-10-01 8:27 ` Wolfgang Lux
` (2 subsequent siblings)
3 siblings, 0 replies; 44+ messages in thread
From: Bill Wood @ 2005-10-01 5:46 UTC (permalink / raw)
To: caml-list
. . .
> 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
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Ant: Re: [Caml-list] Avoiding shared data
2005-10-01 0:07 ` Pal-Kristian Engstad
2005-10-01 5:46 ` Bill Wood
@ 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 21:05 ` Ant: " Martin Chabr
3 siblings, 2 replies; 44+ messages in thread
From: Wolfgang Lux @ 2005-10-01 8:27 UTC (permalink / raw)
To: Pal-Kristian Engstad; +Cc: caml-list, Oliver Bandel
Pal-Kristian Engstad wrote:
> 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.
Oh come on! IMHO, most loops can easily be transformed by using map,
filter,
fold_left, and fold_right. The example given is no exception. The loop
essentially applies some complex code to every element of the list and
includes the result in the output list only if a condition is satisfied
that is computed along with result. This is always the structure of a
fold.
(If the condition were independent from the result one could combine a
filter
and a map.) Thus, a straight forward rewrite of the loop is:
let myfunc l =
let f x result =
if xpred then
let y = verbose_code_using_x x in
if ypred y then
let z = verbose_code_using_y y in
z_expression :: result
else
result
else
result
in
fold_right f l []
Furthermore, I would turn the two if expressions into local functions
let myfunc l =
let g y result =
if ypred y then
let z = verbose_code_using_y y in z_expression :: result
else
result
in let f x result =
if xpred x then
let y = verbose_code_using_x x in g y result
else
result
in fold_right f l []
Regards
Wolfgang
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Ant: Re: [Caml-list] Avoiding shared data
2005-10-01 0:07 ` Pal-Kristian Engstad
2005-10-01 5:46 ` Bill Wood
2005-10-01 8:27 ` Wolfgang Lux
@ 2005-10-01 12:34 ` Oliver Bandel
2005-10-01 13:58 ` Bill Wood
2005-10-01 21:05 ` Ant: " Martin Chabr
3 siblings, 1 reply; 44+ messages in thread
From: Oliver Bandel @ 2005-10-01 12:34 UTC (permalink / raw)
To: caml-list
On Fri, Sep 30, 2005 at 05:07:00PM -0700, Pal-Kristian Engstad wrote:
> On Friday 30 September 2005 03:57 pm, Oliver Bandel wrote:
> > On the other hand: writing mor funtional/recursive code will
> > make you more used to to this...
>
> I've always thought that this was a really bad argument from the ML camp.
It is not a bad argument from the ML camp.
It's always so, that if you have more practice you will be
more used to something and you learn it better.
If you don't practise, learning is abandoned.
This has nothing to do with programming languages.
[...]
> 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!
Some things are better wriiten down functionally, others are better
suited for using impoerative code.
Since I get more and more used to using functional and recursive
code writing, I can better decide, which way is better.
And more and more often I decide to use the recursive style.
In OCaml you are not restricted to it, but if you only use one
style of programming, and never practise the other programming styles,
you can't see, when which programming style/paradigm is better,
and the original poster said something about the distinction
of tail-rec vs. non tail-rec. (It was not about if that style makes sense or not.)
If you practise more of that stuff, and reading some good explanations,
then it's obvious, which solution is tail-rec and which is not.
>
> 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.
Thanks for the link.
>
> The author argues that "Writing loops with tail-recursive function calls is
> the equivalent of writing them with goto???s."
I doubt that the author writes that.
You mean for/while instead of goto's as a substitute for
recursive functions...?!
Ciao,
Oliver
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Ant: Re: [Caml-list] Avoiding shared data
2005-10-01 12:34 ` Oliver Bandel
@ 2005-10-01 13:58 ` Bill Wood
0 siblings, 0 replies; 44+ messages in thread
From: Bill Wood @ 2005-10-01 13:58 UTC (permalink / raw)
To: caml-list
. . .
> > The author argues that "Writing loops with tail-recursive function calls is
> > the equivalent of writing them with goto???s."
>
> I doubt that the author writes that.
> You mean for/while instead of goto's as a substitute for
> recursive functions...?!
Actually, the author does say that. More precisely, Shivers refers to
Steele's characterization of lambda as "gotos with arguments"; I think
the source is the paper "Lambda: the Ultimate GOTO".
-- Bill Wood
bill.wood@acm.org
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Ant: Re: [Caml-list] Avoiding shared data
2005-10-01 8:27 ` Wolfgang Lux
@ 2005-10-01 18:02 ` Wolfgang Lux
2005-10-01 21:50 ` Ant: " Martin Chabr
1 sibling, 0 replies; 44+ messages in thread
From: Wolfgang Lux @ 2005-10-01 18:02 UTC (permalink / raw)
To: Wolfgang Lux; +Cc: Pal-Kristian Engstad, caml-list, Oliver Bandel
Wolfgang Lux wrote:
> let myfunc l =
> let g y result =
> if ypred y then
> let z = verbose_code_using_y y in z_expression :: result
> else
> result
> in let f x result =
> if xpred x then
> let y = verbose_code_using_x x in g y result
> else
> result
> in fold_right f l []
Just correcting myself. The code should use fold_left rather than
fold_right
(and thus switch the parameters in the call as well as that of the local
functions f and g) because the former is tail recursive and therefore
should
be preferred in a strict language (have been programming too much
Haskell
lately where a right fold is better).
Wolfghang
^ permalink raw reply [flat|nested] 44+ messages in thread
* Ant: Re: Ant: Re: [Caml-list] Avoiding shared data
2005-10-01 0:07 ` Pal-Kristian Engstad
` (2 preceding siblings ...)
2005-10-01 12:34 ` Oliver Bandel
@ 2005-10-01 21:05 ` Martin Chabr
2005-10-03 0:41 ` skaller
3 siblings, 1 reply; 44+ messages in thread
From: Martin Chabr @ 2005-10-01 21:05 UTC (permalink / raw)
To: Pal-Kristian Engstad; +Cc: caml-list
Hello Pal-Kristian,
I agree with you that functional code written in a
tail recursive style is hard to read. Sometimes you
have to do it that way if you want to avoid a stack
overflow.
I hope that one day functional language compilers will
do that optimization for you - convert a
non-tail-recursive code into a tail-recursive one. Do
you know of some progress in that direction?
Regards,
Martin
--- Pal-Kristian Engstad <pal_engstad@naughtydog.com>
wrote:
> 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!
___________________________________________________________
Was denken Sie über E-Mail? Wir hören auf Ihre Meinung: http://surveylink.yahoo.com/wix/p0379378.aspx
^ permalink raw reply [flat|nested] 44+ messages in thread
* Ant: Re: Ant: Re: [Caml-list] Avoiding shared data
2005-09-30 22:57 ` Oliver Bandel
2005-10-01 0:07 ` Pal-Kristian Engstad
@ 2005-10-01 21:36 ` Martin Chabr
2005-10-03 11:51 ` getting used to FP-programming (Re: Ant: Re: Ant: Re: [Caml-list] Avoiding shared data) Oliver Bandel
1 sibling, 1 reply; 44+ messages in thread
From: Martin Chabr @ 2005-10-01 21:36 UTC (permalink / raw)
To: Oliver Bandel; +Cc: caml-list
Hello Oliver,
I am trying to find a programming style within the
spectrum of possibilities which OCaml supports. This
programming style should be easy to produce, easy to
read and efficient in runtime.
Sometimes a nested system of "for" or "while" loops
appears simpler to me than a system of recursive
calls. Sometimes such systems of recursive calls
remind me of undisciplined goto jumps.
There is an excellent OCaml tutorial at:
http://www.ocaml-tutorial.org/.
In this tutorial the author gives a simple example of
a stack-blowing, non-tail-recursive code. The
following tail-recursive version takes two functions
instead of one and is relatively much more complex. In
general, for the real world problems, it is much
worse. I cite the author:
"That was a brief overview of tail recursion, but in
real world situations determining if a function is
tail recursive can be quite hard." I believe him.
This is at:
http://www.ocaml-tutorial.org/if_statements,_loops_and_recursion
section tail recursion.
I think that some problems, like simple operations on
lists, can be easier described by pattern matching and
recursion, whereas for others it appears more natural
to take loops.
I also think that what looks simple or not depends on
the person. I myself have spent half of my life with
imperative languages.
Regards,
Martin
--- Oliver Bandel <oliver@first.in-berlin.de> wrote:
> On Mon, Sep 26, 2005 at 11:07:30PM +0200, Martin
> Chabr wrote:
> > Hello William,
> >
> > I am using a mutable record. I am programming this
> 90%
> > in the imperative (non-functional) style, so that
> I
> > can rewrite critical parts into Fortran easily.
> > Another reason is, I am an intermediate user and
> > finding out whether the recursion is a tail-one or
> not
> > is difficult for me.
>
> When you 90% of your code are writing in imperative
> style
> and do not go deeper into the functional/recursive
> world, you will never be able to distinguish between
> tail-rec and non-tail-rec style.
>
> But: It is not really hard to find the distinction
> betwen
> the two styles, but often the explanations are not
> made
> well.
> Sometimes it's only one or two words in an
> explanation about
> tail-rec/non-tail-rec that must be substituted by
> other words,
> and the distinction can be made visible very easy.
>
> On the other hand: writing mor funtional/recursive
> code will
> make you more used to to this...
>
> Ciao,
> Oliver
>
> _______________________________________________
> Caml-list mailing list. Subscription management:
>
http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list
> Archives: http://caml.inria.fr
> Beginner's list:
> http://groups.yahoo.com/group/ocaml_beginners
> Bug reports: http://caml.inria.fr/bin/caml-bugs
>
___________________________________________________________
Was denken Sie über E-Mail? Wir hören auf Ihre Meinung: http://surveylink.yahoo.com/wix/p0379378.aspx
^ permalink raw reply [flat|nested] 44+ messages in thread
* Ant: Re: Ant: Re: [Caml-list] Avoiding shared data
2005-10-01 8:27 ` Wolfgang Lux
2005-10-01 18:02 ` Wolfgang Lux
@ 2005-10-01 21:50 ` Martin Chabr
1 sibling, 0 replies; 44+ messages in thread
From: Martin Chabr @ 2005-10-01 21:50 UTC (permalink / raw)
To: Wolfgang Lux; +Cc: caml-list
Hello Wolfgang,
you are quite right, most loops can easily be
transformed by using map, filter, fold_left or
fold_right. I just tend to forget about it or find it
uneasy if the problem is more complex. It may be just
a matter of habit.
Regards,
Martin
--- Wolfgang Lux <wlux@uni-muenster.de> schrieb:
> Pal-Kristian Engstad wrote:
>
> > The author argues that "Writing loops with
> tail-recursive function
> > calls is
> > the equivalent of writing them with gotos." 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.
>
> Oh come on! IMHO, most loops can easily be
> transformed by using map,
> filter,
> fold_left, and fold_right. The example given is no
> exception. The loop
> essentially applies some complex code to every
> element of the list and
> includes the result in the output list only if a
> condition is satisfied
> that is computed along with result. This is always
> the structure of a
> fold.
> (If the condition were independent from the result
> one could combine a
> filter
> and a map.) Thus, a straight forward rewrite of the
> loop is:
>
> let myfunc l =
> let f x result =
> if xpred then
> let y = verbose_code_using_x x in
> if ypred y then
> let z = verbose_code_using_y y in
> z_expression :: result
> else
> result
> else
> result
> in
> fold_right f l []
>
> Furthermore, I would turn the two if expressions
> into local functions
>
> let myfunc l =
> let g y result =
> if ypred y then
> let z = verbose_code_using_y y in
> z_expression :: result
> else
> result
> in let f x result =
> if xpred x then
> let y = verbose_code_using_x x in g y
> result
> else
> result
> in fold_right f l []
>
> Regards
> Wolfgang
>
> _______________________________________________
> Caml-list mailing list. Subscription management:
>
http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list
> Archives: http://caml.inria.fr
> Beginner's list:
> http://groups.yahoo.com/group/ocaml_beginners
> Bug reports: http://caml.inria.fr/bin/caml-bugs
>
___________________________________________________________
Gesendet von Yahoo! Mail - Jetzt mit 1GB Speicher kostenlos - Hier anmelden: http://mail.yahoo.de
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Ant: Re: Ant: Re: [Caml-list] Avoiding shared data
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
0 siblings, 2 replies; 44+ messages in thread
From: skaller @ 2005-10-03 0:41 UTC (permalink / raw)
To: Martin Chabr; +Cc: Pal-Kristian Engstad, caml-list
On Sat, 2005-10-01 at 23:05 +0200, Martin Chabr wrote:
> Hello Pal-Kristian,
>
> I agree with you that functional code written in a
> tail recursive style is hard to read. Sometimes you
> have to do it that way if you want to avoid a stack
> overflow.
>
> I hope that one day functional language compilers will
> do that optimization for you - convert a
> non-tail-recursive code into a tail-recursive one. Do
> you know of some progress in that direction?
Isn't that just CPS?
--
John Skaller <skaller at users dot sf dot net>
Felix, successor to C++: http://felix.sf.net
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Ant: Re: Ant: Re: [Caml-list] Avoiding shared data
2005-10-03 0:41 ` skaller
@ 2005-10-03 1:13 ` Seth J. Fogarty
2005-10-03 13:09 ` Thomas Fischbacher
1 sibling, 0 replies; 44+ messages in thread
From: Seth J. Fogarty @ 2005-10-03 1:13 UTC (permalink / raw)
To: caml-list
On 10/2/05, skaller <skaller@users.sourceforge.net> wrote:
> On Sat, 2005-10-01 at 23:05 +0200, Martin Chabr wrote:
> > Hello Pal-Kristian,
> >
> > I agree with you that functional code written in a
> > tail recursive style is hard to read. Sometimes you
> > have to do it that way if you want to avoid a stack
> > overflow.
> >
> > I hope that one day functional language compilers will
> > do that optimization for you - convert a
> > non-tail-recursive code into a tail-recursive one. Do
> > you know of some progress in that direction?
>
> Isn't that just CPS?
--
Seth Fogarty sfogarty@[gmail.com|rice.edu|livejournal]
Neep-neep at large AIM: Sorrath
"I know there are people in this world who do not love their fellow
human beings - and I hate people like that" --Tom Lehrer.
^ permalink raw reply [flat|nested] 44+ messages in thread
* getting used to FP-programming (Re: Ant: Re: Ant: Re: [Caml-list] Avoiding shared data)
2005-10-01 21:36 ` Ant: Re: Ant: " Martin Chabr
@ 2005-10-03 11:51 ` Oliver Bandel
0 siblings, 0 replies; 44+ messages in thread
From: Oliver Bandel @ 2005-10-03 11:51 UTC (permalink / raw)
To: caml-list
Hello Martin,
On Sat, Oct 01, 2005 at 11:36:08PM +0200, Martin Chabr wrote:
> Hello Oliver,
>
> I am trying to find a programming style within the
> spectrum of possibilities which OCaml supports. This
> programming style should be easy to produce, easy to
> read and efficient in runtime.
>
> Sometimes a nested system of "for" or "while" loops
> appears simpler to me than a system of recursive
> calls. Sometimes such systems of recursive calls
> remind me of undisciplined goto jumps.
[...]
> general, for the real world problems, it is much
> worse. I cite the author:
> "That was a brief overview of tail recursion, but in
> real world situations determining if a function is
> tail recursive can be quite hard." I believe him.
I doubt it is.
Or maybe if the people write functions that are some
pages of code long. But it's better to keep the functions short,
and FP makes this very easy.
[...]
> I think that some problems, like simple operations on
> lists, can be easier described by pattern matching and
> recursion, whereas for others it appears more natural
> to take loops.
Yes, but when you are used to FP-style and recursions
the amount of problems one would rather use the
for/while loops for, gets smaller.
I just dome days ago saw this on an example-code I wrote
in a discussion on the berlin' Linux-User-Groups mailing list
(I'm doing some marketing for OCaml;-))
I first thought, well the better version is with loops.
But I tried the recursive definition and it was astouningly
easy to read. :)
So IMHO it's how often you tried the different programming style,
what makes you thinking different about this.
>
> I also think that what looks simple or not depends on
> the person. I myself have spent half of my life with
> imperative languages.
Mee too for many years, and "depends on the person" could also be said
as: "depends on the experience of the person", and as I more and more
get used to FP constructs, I see the problem solving diferently than
some time ago.
Ciao,
Oliver
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Ant: Re: Ant: Re: [Caml-list] Avoiding shared data
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
` (2 more replies)
1 sibling, 3 replies; 44+ messages in thread
From: Thomas Fischbacher @ 2005-10-03 13:09 UTC (permalink / raw)
To: skaller; +Cc: Martin Chabr, Pal-Kristian Engstad, caml-list
On Mon, 3 Oct 2005, skaller wrote:
> > I hope that one day functional language compilers will
> > do that optimization for you - convert a
> > non-tail-recursive code into a tail-recursive one. Do
> > you know of some progress in that direction?
>
> Isn't that just CPS?
He presumably wanted to see a different thing, e.g.
automatically transforming
let rec fac1 x =
if x = 0
then 1
else x*(fac1 (x-1))
;;
into
let fac2 x =
let rec walk so_far todo =
if todo = 0
then so_far
else walk (todo*so_far) (todo-1)
in walk 1 x
;;
My impression is that it may indeed be possible to do something like this
for simple applications, but that the cases that can be covered
automatically presumably are so limited that an experienced programmer
will usually want to attack them by going to a higher form of abstraction
and not waste time on such things anyway.
I think that Olin Shivers indeed does have a valid point in pointing out
that writing loops in tail-recursive style has major disadvantages.
However, my impression still is that as soon as someone thinks in terms of
"I have to write a loop for this", chances are good that he may improve
his design by going back one step and ask the question "what do I want to
use that loop for?". In quite many situations, it is possible to express
one's thoughts more directly via other means, such as Array.map,
fold_left, etc.
What I (as a pedestrian) especially do not like about loops is that it is
much easier to make off-by-one errors than with any form of recursion
which contains a base-case/recursive-case analysis.
Unfortunately, the OCaml native code compiler apparently is not yet smart
enough to optimize code written in such a higher-order style well enough
so that it can compete with imperative or tail-recursive code in
time-critical applications. (Though quite many applications in fact are
not.) At present, one can expect to lose about a factor of ~3 in
performance.
Example:
===>
let timing_apply f x =
let t0 = Unix.gettimeofday() in
let f_x = f x in
let t1 = Unix.gettimeofday() in
(f_x,t1-.t0)
;;
let my_array_fold_left f init arr =
let len = Array.length arr in
let rec walk so_far pos =
if pos=len
then so_far
else walk (f so_far arr.(pos)) (1+pos)
in walk init 0
;;
let test m n =
let arr =
Array.init m
(fun j -> Array.init n (fun k -> j*k+k))
in
let scratchpad = ref 0 in
(* -- *)
let rec frobenius1 mx =
Array.fold_left
(fun so_far row ->
Array.fold_left
(fun so_far entry ->
so_far+entry*entry)
so_far row)
0 mx
in
let frobenius2 mx =
my_array_fold_left
(fun so_far row ->
my_array_fold_left
(fun so_far entry ->
so_far+entry*entry)
so_far row)
0 mx
in
let frobenius3 mx =
begin
scratchpad := 0;
for i=0 to (Array.length mx)-1 do
let row = mx.(i) in
for j=0 to (Array.length row)-1 do
scratchpad:= !scratchpad + row.(j)*row.(j);
done;
done;
!scratchpad
end
in
let frobenius4 mx =
let nr_rows = Array.length mx in
let rec walk_rows so_far nr_row =
if nr_row = nr_rows
then so_far
else
let row = mx.(nr_row) in
let len_row = Array.length row in
let rec walk_cols so_far nr_col =
if nr_col = len_row
then so_far
else walk_cols (so_far+row.(nr_col)*row.(nr_col)) (1+nr_col)
in
walk_rows (walk_cols so_far 0) (1+nr_row)
in
walk_rows 0 0
in
let frobenius5 mx =
let nr_rows = Array.length mx in
let rec walk_rows so_far nr_row =
if nr_row = nr_rows
then so_far
else
let row = mx.(nr_row) in
let len_row = Array.length row in
let rec walk_cols row so_far nr_col =
if nr_col = len_row
then so_far
else walk_cols row (so_far+row.(nr_col)*row.(nr_col)) (1+nr_col)
in
walk_rows (walk_cols row so_far 0) (1+nr_row)
in
walk_rows 0 0
in
let compute_n_times n f x =
let rec walk k =
if k = n then f x
else
let () = ignore(f x) in
walk (k+1)
in walk 1
in
Array.map
(fun f -> timing_apply (compute_n_times 1000 f) arr)
[|frobenius1;frobenius2;frobenius3;frobenius4;frobenius5|]
;;
let result = test 1000 3 in
Array.iteri (fun nr (_,t) -> Printf.printf "%d: %f\n" (1+nr) t) result
;;
<===
ocamlc:
1: 0.987257
2: 1.196910
3: 0.709074
4: 0.858948
5: 0.984935
ocamlopt:
1: 0.066404
2: 0.075691
3: 0.025450
4: 0.025756
5: 0.023472
--
regards, tf@cip.physik.uni-muenchen.de (o_
Thomas Fischbacher - http://www.cip.physik.uni-muenchen.de/~tf //\
(lambda (n) ((lambda (p q r) (p p q r)) (lambda (g x y) V_/_
(if (= x 0) y (g g (- x 1) (* x y)))) n 1)) (Debian GNU)
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Ant: Re: Ant: Re: [Caml-list] Avoiding shared data
2005-10-03 13:09 ` Thomas Fischbacher
@ 2005-10-03 14:57 ` skaller
2005-10-03 20:03 ` Ant: " Martin Chabr
2005-10-05 11:14 ` Andrej Bauer
2 siblings, 0 replies; 44+ messages in thread
From: skaller @ 2005-10-03 14:57 UTC (permalink / raw)
To: Thomas Fischbacher; +Cc: Martin Chabr, Pal-Kristian Engstad, caml-list
On Mon, 2005-10-03 at 15:09 +0200, Thomas Fischbacher wrote:
> On Mon, 3 Oct 2005, skaller wrote:
>
> > > I hope that one day functional language compilers will
> > > do that optimization for you - convert a
> > > non-tail-recursive code into a tail-recursive one. Do
> > > you know of some progress in that direction?
> >
> > Isn't that just CPS?
>
> He presumably wanted to see a different thing, e.g.
> automatically transforming
I know. But his comment 'that's different' is inadequate.
CPS transforms code so there are no function calls at all,
(procedural form), or, in functional form, every function
contains exactly one call which is always in tail position.
So it certainly does what is required. Therefore the
question is nonsense. The real question is more like
asking if it is possible to transform a routine
using O(n^k) store into one using O(n^j) store, where j < k.
It is always possible to eliminate recursion: for example,
a recursive descent of a simple tree can always be replaced by a using
an iterator .. of course the iterator will have to retain
a list of parent nodes to allow the traversal, so eliminating
the 'recursion' does not save any storage.
--
John Skaller <skaller at users dot sf dot net>
Felix, successor to C++: http://felix.sf.net
^ permalink raw reply [flat|nested] 44+ messages in thread
* Ant: Re: Ant: Re: Ant: Re: [Caml-list] Avoiding shared data
2005-10-03 13:09 ` Thomas Fischbacher
2005-10-03 14:57 ` skaller
@ 2005-10-03 20:03 ` Martin Chabr
2005-10-03 20:25 ` Thomas Fischbacher
` (2 more replies)
2005-10-05 11:14 ` Andrej Bauer
2 siblings, 3 replies; 44+ messages in thread
From: Martin Chabr @ 2005-10-03 20:03 UTC (permalink / raw)
To: Thomas Fischbacher; +Cc: caml-list
Thomas,
what I am especially concerned about is the stack
overflow for non-tail-recursive programs. Speed is of
less importance.
By the way, we are diverting from the subject of this
thread and from the main cause of my concern:
Avoiding shared data. Why is it done that way? Who
wants to have an array or list of identical records or
sub-arrays or other sub-structures which are all
updated at the same time in the same way? In other
words, who wants to have an array or a list of
pointers which are pointing to the same thing?
Does it ever happen in OCaml if programming is done in
a purely functional way? Does it happen in Haskell?
Martin
--- Thomas Fischbacher
<Thomas.Fischbacher@Physik.Uni-Muenchen.DE> schrieb:
>
> On Mon, 3 Oct 2005, skaller wrote:
>
> > > I hope that one day functional language
> compilers will
> > > do that optimization for you - convert a
> > > non-tail-recursive code into a tail-recursive
> one. Do
> > > you know of some progress in that direction?
> >
> > Isn't that just CPS?
>
> He presumably wanted to see a different thing, e.g.
> automatically transforming
>
>
> let rec fac1 x =
> if x = 0
> then 1
> else x*(fac1 (x-1))
> ;;
>
> into
>
> let fac2 x =
> let rec walk so_far todo =
> if todo = 0
> then so_far
> else walk (todo*so_far) (todo-1)
> in walk 1 x
> ;;
>
>
> My impression is that it may indeed be possible to
> do something like this
> for simple applications, but that the cases that can
> be covered
> automatically presumably are so limited that an
> experienced programmer
> will usually want to attack them by going to a
> higher form of abstraction
> and not waste time on such things anyway.
>
> I think that Olin Shivers indeed does have a valid
> point in pointing out
> that writing loops in tail-recursive style has major
> disadvantages.
> However, my impression still is that as soon as
> someone thinks in terms of
> "I have to write a loop for this", chances are good
> that he may improve
> his design by going back one step and ask the
> question "what do I want to
> use that loop for?". In quite many situations, it is
> possible to express
> one's thoughts more directly via other means, such
> as Array.map,
> fold_left, etc.
>
> What I (as a pedestrian) especially do not like
> about loops is that it is
> much easier to make off-by-one errors than with any
> form of recursion
> which contains a base-case/recursive-case analysis.
>
>
> Unfortunately, the OCaml native code compiler
> apparently is not yet smart
> enough to optimize code written in such a
> higher-order style well enough
> so that it can compete with imperative or
> tail-recursive code in
> time-critical applications. (Though quite many
> applications in fact are
> not.) At present, one can expect to lose about a
> factor of ~3 in
> performance.
>
> Example:
>
> ===>
> let timing_apply f x =
> let t0 = Unix.gettimeofday() in
> let f_x = f x in
> let t1 = Unix.gettimeofday() in
> (f_x,t1-.t0)
> ;;
>
> let my_array_fold_left f init arr =
> let len = Array.length arr in
> let rec walk so_far pos =
> if pos=len
> then so_far
> else walk (f so_far arr.(pos)) (1+pos)
> in walk init 0
> ;;
>
>
> let test m n =
> let arr =
> Array.init m
> (fun j -> Array.init n (fun k -> j*k+k))
> in
> let scratchpad = ref 0 in
> (* -- *)
> let rec frobenius1 mx =
> Array.fold_left
> (fun so_far row ->
> Array.fold_left
> (fun so_far entry ->
> so_far+entry*entry)
> so_far row)
> 0 mx
> in
> let frobenius2 mx =
> my_array_fold_left
> (fun so_far row ->
> my_array_fold_left
> (fun so_far entry ->
> so_far+entry*entry)
> so_far row)
> 0 mx
> in
> let frobenius3 mx =
> begin
> scratchpad := 0;
> for i=0 to (Array.length mx)-1 do
> let row = mx.(i) in
> for j=0 to (Array.length row)-1 do
> scratchpad:= !scratchpad + row.(j)*row.(j);
> done;
> done;
> !scratchpad
> end
> in
> let frobenius4 mx =
> let nr_rows = Array.length mx in
> let rec walk_rows so_far nr_row =
> if nr_row = nr_rows
> then so_far
> else
> let row = mx.(nr_row) in
> let len_row = Array.length row in
> let rec walk_cols so_far nr_col =
> if nr_col = len_row
> then so_far
> else walk_cols (so_far+row.(nr_col)*row.(nr_col))
> (1+nr_col)
> in
> walk_rows (walk_cols so_far 0) (1+nr_row)
> in
> walk_rows 0 0
> in
> let frobenius5 mx =
> let nr_rows = Array.length mx in
> let rec walk_rows so_far nr_row =
> if nr_row = nr_rows
> then so_far
> else
> let row = mx.(nr_row) in
> let len_row = Array.length row in
> let rec walk_cols row so_far nr_col =
> if nr_col = len_row
> then so_far
> else walk_cols row
> (so_far+row.(nr_col)*row.(nr_col)) (1+nr_col)
> in
> walk_rows (walk_cols row so_far 0) (1+nr_row)
> in
> walk_rows 0 0
> in
> let compute_n_times n f x =
> let rec walk k =
> if k = n then f x
> else
> let () = ignore(f x) in
> walk (k+1)
> in walk 1
> in
> Array.map
> (fun f -> timing_apply (compute_n_times 1000 f)
> arr)
>
>
[|frobenius1;frobenius2;frobenius3;frobenius4;frobenius5|]
> ;;
>
> let result = test 1000 3 in
> Array.iteri (fun nr (_,t) -> Printf.printf "%d:
> %f\n" (1+nr) t) result
> ;;
> <===
>
> ocamlc:
>
> 1: 0.987257
> 2: 1.196910
> 3: 0.709074
> 4: 0.858948
> 5: 0.984935
>
> ocamlopt:
>
=== message truncated ===
___________________________________________________________
Gesendet von Yahoo! Mail - Jetzt mit 1GB Speicher kostenlos - Hier anmelden: http://mail.yahoo.de
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Ant: Re: Ant: Re: Ant: Re: [Caml-list] Avoiding shared data
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 2:53 ` skaller
2 siblings, 0 replies; 44+ messages in thread
From: Thomas Fischbacher @ 2005-10-03 20:25 UTC (permalink / raw)
To: Martin Chabr; +Cc: caml-list
On Mon, 3 Oct 2005, Martin Chabr wrote:
> Avoiding shared data. Why is it done that way? Who
> wants to have an array or list of identical records or
> sub-arrays or other sub-structures which are all
> updated at the same time in the same way?
Thoughts about substructure updates and sharing structure do not mix.
There are situations where the one way to think about things is
appropriate, and there are situations when it's the other one.
> In other
> words, who wants to have an array or a list of
> pointers which are pointing to the same thing?
Suppose I give you a tree representing the filesystem structure on my
machine. Now I ask you to map this to the tree describing the filesystem
with one directory renamed and another one (and everythinbg beneath it)
deleted. You surely do not want to copy the entire tree, so this is an
example where sharing structure perfectly makes sense. And as you do not
destructively modify the data in the nodes, it does not matter at all for
the semantics of the program that you actually share a lot of data.
--
regards, tf@cip.physik.uni-muenchen.de (o_
Thomas Fischbacher - http://www.cip.physik.uni-muenchen.de/~tf //\
(lambda (n) ((lambda (p q r) (p p q r)) (lambda (g x y) V_/_
(if (= x 0) y (g g (- x 1) (* x y)))) n 1)) (Debian GNU)
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Ant: Re: Ant: Re: Ant: Re: [Caml-list] Avoiding shared data
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 2:53 ` skaller
2 siblings, 1 reply; 44+ messages in thread
From: Jon Harrop @ 2005-10-03 21:08 UTC (permalink / raw)
To: caml-list
On Monday 03 October 2005 21:03, Martin Chabr wrote:
> what I am especially concerned about is the stack
> overflow for non-tail-recursive programs. Speed is of
> less importance.
Yes. Many useful algorithms are non-tail recursive and do not cause stack
overflows, e.g. those that recurse O(log n) times.
> By the way, we are diverting from the subject of this
> thread and from the main cause of my concern:
>
> Avoiding shared data. Why is it done that way? Who
> wants to have an array or list of identical records or
> sub-arrays or other sub-structures which are all
> updated at the same time in the same way? In other
> words, who wants to have an array or a list of
> pointers which are pointing to the same thing?
If you mean this:
# let a = Array.make 3 (ref 0) in (a.(0) := 3; a);;
- : int ref array = [|{contents = 3}; {contents = 3}; {contents = 3}|]
I don't want arrays of elements referencing the same value. So I don't create
them.
> Does it ever happen in OCaml if programming is done in
> a purely functional way?
If you mean "is referential transparency useful?" then the answer is
definitely yes. I use data structures that share data all the time but not in
the form of an array or list of the same repeated value.
For example, computing set unions, differences and intersections using the Set
module reuses branches of old tree when possible. This reduces the asymptotic
algorithmic complexity of these operations so they can run asymptotically
faster than imperative implementations.
> Does it happen in Haskell?
You'll get a suboptimal answer to such questions on this list.
--
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
Objective CAML for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Ant: Re: Ant: Re: Ant: Re: [Caml-list] Avoiding shared data
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 2:53 ` skaller
2005-10-04 16:15 ` Brian Hurt
2005-10-04 18:09 ` Ant: Re: Ant: Re: Ant: Re: Ant: Re: [Caml-list] Avoiding shared data Martin Chabr
2 siblings, 2 replies; 44+ messages in thread
From: skaller @ 2005-10-04 2:53 UTC (permalink / raw)
To: Martin Chabr; +Cc: Thomas Fischbacher, caml-list
On Mon, 2005-10-03 at 22:03 +0200, Martin Chabr wrote:
> Avoiding shared data. Why is it done that way? Who
> wants to have an array or list of identical records or
> sub-arrays or other sub-structures which are all
> updated at the same time in the same way?
Mutable shared data is very useful: caching is
an obvious example where this is precisely what you want.
--
John Skaller <skaller at users dot sf dot net>
Felix, successor to C++: http://felix.sf.net
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: [Caml-list] Avoiding shared data
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 18:09 ` Ant: Re: Ant: Re: Ant: Re: Ant: Re: [Caml-list] Avoiding shared data Martin Chabr
1 sibling, 1 reply; 44+ messages in thread
From: Brian Hurt @ 2005-10-04 16:15 UTC (permalink / raw)
To: skaller; +Cc: Martin Chabr, Thomas Fischbacher, caml-list
On Tue, 4 Oct 2005, skaller wrote:
> Mutable shared data is very useful: caching is
> an obvious example where this is precisely what you want.
Also, occassionally mutable data allows you to do something in O(1)
instead of O(log N). If this extra cost is in your inner loop, it can
slow the whole algorithm down by a factor of 10-30 fold easy. Graph
algorithms are especially bad for this. Want to get a name for yourself?
Come up with a way to represent cyclic graphs in a purely functional way
such that given any arbtirary node, I can find out what other nodes it has
edges to (and what their weights are) in O(1).
Brian
^ permalink raw reply [flat|nested] 44+ messages in thread
* FP/IP and performance (in general) and Patterns... (Re: [Caml-list] Avoiding shared data)
2005-10-04 16:15 ` Brian Hurt
@ 2005-10-04 16:47 ` Oliver Bandel
2005-10-04 22:38 ` Michael Wohlwend
` (2 more replies)
0 siblings, 3 replies; 44+ messages in thread
From: Oliver Bandel @ 2005-10-04 16:47 UTC (permalink / raw)
To: caml-list
Hello,
is there a general overvie (paper or book), where
functional and imperative approaches to solve a problem are
compared directly?
Most often people say, imperative is faster in most of all
cases, and only in some cases FP might be faster.
If there is a paper/book about problem solving and performance,
comparing different approaches I would be happy to have a pointer
to it.
Also it would be nice to find something about how
classical imperative style, OO-style and FP-style
are solving problems, and which patterns can be done
easier in the one or the other way.
I recently had a discussion about some OO-patterns
( so called "GoF"-Book) and tried to solve some of them with
OCamls module system.
Adapter and bridge was talked about. Adapter was easy in writing a simple
wrapper.
Bridge could be done with a functor. :)
So, if there are direct translations possible, where to find
comparisons?
Another interesting theme in this respect is: If not only some patterns
were adapted to Fp, but the whole problem solving approach is different,
which patterns will be unnevcessary then, because the whole structure of
the software will be different...?!
Ciao,
Oliver
^ permalink raw reply [flat|nested] 44+ messages in thread
* Ant: Re: Ant: Re: Ant: Re: Ant: Re: [Caml-list] Avoiding shared data
2005-10-03 21:08 ` Jon Harrop
@ 2005-10-04 18:06 ` Martin Chabr
2005-10-04 18:32 ` Jon Harrop
0 siblings, 1 reply; 44+ messages in thread
From: Martin Chabr @ 2005-10-04 18:06 UTC (permalink / raw)
To: Jon Harrop; +Cc: caml-list
--- Jon Harrop <jon@ffconsultancy.com> wrote:
> If you mean this:
>
> # let a = Array.make 3 (ref 0) in (a.(0) := 3; a);;
> - : int ref array = [|{contents = 3}; {contents =
> 3}; {contents = 3}|]
>
> I don't want arrays of elements referencing the same
> value. So I don't create
> them.
I do not disagree. The trouble on my side is that it
is very easy to get them and difficult not to get them
or get rid of them, once the programs get more
complex.
Martin
___________________________________________________________
Was denken Sie über E-Mail? Wir hören auf Ihre Meinung: http://surveylink.yahoo.com/wix/p0379378.aspx
^ permalink raw reply [flat|nested] 44+ messages in thread
* Ant: Re: Ant: Re: Ant: Re: Ant: Re: [Caml-list] Avoiding shared data
2005-10-04 2:53 ` skaller
2005-10-04 16:15 ` Brian Hurt
@ 2005-10-04 18:09 ` Martin Chabr
2005-10-05 8:42 ` skaller
1 sibling, 1 reply; 44+ messages in thread
From: Martin Chabr @ 2005-10-04 18:09 UTC (permalink / raw)
To: skaller; +Cc: caml-list
--- skaller <skaller@users.sourceforge.net> wrote:
> On Mon, 2005-10-03 at 22:03 +0200, Martin Chabr
> wrote:
>
> > Avoiding shared data. Why is it done that way? Who
> > wants to have an array or list of identical
> records or
> > sub-arrays or other sub-structures which are all
> > updated at the same time in the same way?
>
> Mutable shared data is very useful: caching is
> an obvious example where this is precisely what you
> want.
>
> --
> John Skaller <skaller at users dot sf dot net>
> Felix, successor to C++: http://felix.sf.net
>
>
This sounds very interesting. Can you say a little
more about it please?
Martin
___________________________________________________________
Was denken Sie über E-Mail? Wir hören auf Ihre Meinung: http://surveylink.yahoo.com/wix/p0379378.aspx
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Ant: Re: Ant: Re: Ant: Re: Ant: Re: [Caml-list] Avoiding shared data
2005-10-04 18:06 ` Ant: " Martin Chabr
@ 2005-10-04 18:32 ` Jon Harrop
0 siblings, 0 replies; 44+ messages in thread
From: Jon Harrop @ 2005-10-04 18:32 UTC (permalink / raw)
To: caml-list
On Tuesday 04 October 2005 19:06, you wrote:
> I do not disagree. The trouble on my side is that it
> is very easy to get them and difficult not to get them
> or get rid of them, once the programs get more
> complex.
Yes, misuse of Array.make is certainly a caveat. The easiest solution is to
use Array.init instead.
--
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
Objective CAML for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: FP/IP and performance (in general) and Patterns... (Re: [Caml-list] Avoiding shared data)
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-05 0:45 ` Brian Hurt
2 siblings, 1 reply; 44+ messages in thread
From: Michael Wohlwend @ 2005-10-04 22:38 UTC (permalink / raw)
To: caml-list
On Tuesday 04 October 2005 18:47, Oliver Bandel wrote:
>
> So, if there are direct translations possible, where to find
> comparisons?
>
there is a paper "Design Patterns in OCaml" which describes various patterns:
http://people.csail.mit.edu/dnj/teaching/6898/projects/vicente-wagner.pdf
cheers,
Michael
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: FP/IP and performance (in general) and Patterns... (Re: [Caml-list] Avoiding shared data)
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-04 22:39 ` Christopher A. Watford
2005-10-04 23:14 ` Jon Harrop
2005-10-05 12:10 ` Oliver Bandel
2005-10-05 0:45 ` Brian Hurt
2 siblings, 2 replies; 44+ messages in thread
From: Christopher A. Watford @ 2005-10-04 22:39 UTC (permalink / raw)
To: Oliver Bandel; +Cc: caml-list
On 10/4/05, Oliver Bandel <oliver@first.in-berlin.de> wrote:
> Hello,
>
> is there a general overvie (paper or book), where
> functional and imperative approaches to solve a problem are
> compared directly?
>
> Most often people say, imperative is faster in most of all
> cases, and only in some cases FP might be faster.
>
> If there is a paper/book about problem solving and performance,
> comparing different approaches I would be happy to have a pointer
> to it.
>
> Also it would be nice to find something about how
> classical imperative style, OO-style and FP-style
> are solving problems, and which patterns can be done
> easier in the one or the other way.
>
> I recently had a discussion about some OO-patterns
> ( so called "GoF"-Book) and tried to solve some of them with
> OCamls module system.
> Adapter and bridge was talked about. Adapter was easy in writing a simple
> wrapper.
> Bridge could be done with a functor. :)
>
> So, if there are direct translations possible, where to find
> comparisons?
>
> Another interesting theme in this respect is: If not only some patterns
> were adapted to Fp, but the whole problem solving approach is different,
> which patterns will be unnevcessary then, because the whole structure of
> the software will be different...?!
>
> Ciao,
> Oliver
Sigh, your question only begs for trolls to pop out of the corners.
It would probably be best to keep these questions off this list. Far
too often they go off into the deep end of the 'my language is better
than your language' debates. Obviously members of this list are going
to be biased towards functional languages and will probably give you
biased articles to read or biased papers. Not necessarily biased in a
bad way, just more likely to show functional languages in a good
light.
A poor place to start reading on the subject of what language is best
is The Computer Language Shootout [1]. An even worse place to start
reading is this list.
The actual performance for any program will depend largely on your
ability to program well for the language and for the specific compiler
you choose.
I would say it's obvious that some patterns are easier to *write* in a
certain language, but that hardly shows which language is *best* speed
wise. Your example shows one pattern functional languages are well
suited for, however, I'm sure an experienced C programmer could show
you an example of that pattern which is both efficient and easy to
read (I know I know people on this list may disagree).
This list is best for asking OCaml questions and is awful for asking
for what language is best for what, nobody agrees.
--
Christopher A. Watford
christopher.watford@gmail.com
[1] http://shootout.alioth.debian.org/
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: FP/IP and performance (in general) and Patterns... (Re: [Caml-list] Avoiding shared data)
2005-10-04 22:39 ` Christopher A. Watford
@ 2005-10-04 23:14 ` Jon Harrop
2005-10-05 12:10 ` Oliver Bandel
1 sibling, 0 replies; 44+ messages in thread
From: Jon Harrop @ 2005-10-04 23:14 UTC (permalink / raw)
To: caml-list
On Tuesday 04 October 2005 23:39, Christopher A. Watford wrote:
> This list is best for asking OCaml questions and is awful for asking
> for what language is best for what, nobody agrees.
Oliver was asking which of three programming paradigms is best under different
circumstances. OCaml provides all three so I think this can be taken as an
OCaml-specific question and is fine for this list.
I for one would be very interested in reading information on this. I'll check
out the design patterns paper - thanks Michael.
My impression is that:
1. Data structure heavy code is often easier to write in a functional style.
See the "n"th-nearest neighbour example from my book:
http://www.ffconsultancy.com/products/ocaml_for_scientists/complete/
2. GUI code is more easily written with a stateful imperative front and often
a functional back end.
I have yet to really exploit OCaml's OO capabilities.
--
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
Objective CAML for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: FP/IP and performance (in general) and Patterns... (Re: [Caml-list] Avoiding shared data)
2005-10-04 22:38 ` Michael Wohlwend
@ 2005-10-05 0:31 ` Jon Harrop
0 siblings, 0 replies; 44+ messages in thread
From: Jon Harrop @ 2005-10-05 0:31 UTC (permalink / raw)
To: caml-list
On Tuesday 04 October 2005 23:38, Michael Wohlwend wrote:
> there is a paper "Design Patterns in OCaml" which describes various
> patterns:
> http://people.csail.mit.edu/dnj/teaching/6898/projects/vicente-wagner.pdf
I think I read this paper some time ago but it was interesting to read it
again. Firstly, it gives only 3 references, doesn't appear to be complete, I
think it is out of date and it appears to be written from the point of view
of a dynamic typer. Secondly, I was never a fan of "design patterns".
As they say, several "design patterns" have trivial counterparts in FPLs,
roughly: Singleton = module structure, Facade = module signature, Command =
currying, Memento = dynamic type checking, and Strategy = HOFs.
The paper repeatedly states that modules cannot be mutually recursive. AFAIK,
this has not been true for some time.
In the section about the "Observer" pattern, they state "a meaningless method
call must be inserted into the code because OCaml's static checker cannot
infer the type of the ...". Can the meaningless method not be replaced with a
type declaration?
Perhaps the "State" pattern can be better represented by reusing polymorphic
variants.
Overall, I'd say that the idea of design patterns is reasonable but the GOFs
work is not relevant to OCaml - the study will need to be redone from
scratch. I am much more interested in the automation of the factoring of code
patterns, although I've yet to actually study it...
--
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
Objective CAML for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: FP/IP and performance (in general) and Patterns... (Re: [Caml-list] Avoiding shared data)
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-04 22:39 ` Christopher A. Watford
@ 2005-10-05 0:45 ` Brian Hurt
2 siblings, 0 replies; 44+ messages in thread
From: Brian Hurt @ 2005-10-05 0:45 UTC (permalink / raw)
To: Oliver Bandel; +Cc: caml-list
On Tue, 4 Oct 2005, Oliver Bandel wrote:
> Most often people say, imperative is faster in most of all
> cases, and only in some cases FP might be faster.
The general argument here is that if the FP solution is faster, the
imperitive language can just implement the FP solution. My answer to that
is that imperitive programming languages discourage you from thinking in
certain ways rather strongly- while the FP solution may be faster, it's
not "natural".
The big advantage of FP programming IMHO is not performance, but instead
*correctness*. With today's multi-gigahertz machines with multi-gigabytes
of memory, performance isn't as critical as it used to be. But
correctness- especially automatically gaurenteed correctness on projects
spanning hundreds of thousands of lines of code and dozens of developers
maintained over decades of time- starts becoming critical. I'd quite
happily trade off 10% performance for correctness, or even 50%
performance.
FP is a huge gain in correctness, because it allows me to *control
mutability*. If I pass a mutable data structure to a block of code there
is an instant implicit contract between the caller and the callee on how
(or wether) to modify the mutable data structure. It doesn't matter what
the contract is- wether it's to not modify the structure at all, to allow
optional modification (either unlimited or only in certain ways), or to
require certain modifications- a dependency between the two different
peices of code exists. And this dependency, this contract, is probably
undocumented and always unchecked by the compiler, which means it's a
maintaince nightmare waiting to happen. One peice of code gets modified
to violate the contract, perhaps even unknowingly, or perhaps due to some
changing requirement, and untouched code thousands of lines away suddenly
breaks.
Note that such a bidirectional dependency can be implemented in functional
code- the called code returns a new copy of the modified structure to the
calling code, which the calling code then adopts and uses. But notice
that such a bidirectional dependency is explicitly stated in the code, and
automatically checked by the compiler. And the calling code has the
option of wether or not to allow the modification (or to use both the old
and the new copy).
Java programmers are begining to tumble to this advantage- notice the
increasing popularity of immutable objects (starting with Int and Float),
and Java Beans.
> I recently had a discussion about some OO-patterns
> ( so called "GoF"-Book) and tried to solve some of them with
> OCamls module system.
> Adapter and bridge was talked about. Adapter was easy in writing a simple
> wrapper.
> Bridge could be done with a functor. :)
Some of the patterns are doable with modules. Singleton, for example, is
a classic module pattern. Many of the patterns aren't, however. An
important comment here is that modules are NOT weird and broken objects.
A better point of comparison is C++ templates, except that 95+% of the use
of templates in C++ is to implement universal types, i.e. a C++ programmer
writes "list<A>" where an Ocaml programmer would write "'a list".
>
> Another interesting theme in this respect is: If not only some patterns
> were adapted to Fp, but the whole problem solving approach is different,
> which patterns will be unnevcessary then, because the whole structure of
> the software will be different...?!
There are patterns in every programming idiom. The GoF book was just
Object Oriented patterns- but there are procedural patterns, and
functional patterns, and logic patterns, etc.
Brian
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Ant: Re: Ant: Re: Ant: Re: Ant: Re: [Caml-list] Avoiding shared data
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
0 siblings, 0 replies; 44+ messages in thread
From: skaller @ 2005-10-05 8:42 UTC (permalink / raw)
To: Martin Chabr; +Cc: caml-list
On Tue, 2005-10-04 at 20:09 +0200, Martin Chabr wrote:
> > Mutable shared data is very useful: caching is
> > an obvious example where this is precisely what you
> > want.
> This sounds very interesting. Can you say a little
> more about it please?
Well others know more about techniques like HashConsing
and memoisation than I do .. but basically it is sometimes
useful for a pure function which is expensive to evaluate,
to have a cache of results already computed.
For example, in Felix I have to do 'lookup' to bind
string names of functions to entries in the symbol table.
The lookup is very expensive for functions, because Felix
supports overloading, which means the argument type has
to be calculated, and unification against bound signatures
of candidates is used to select the most specialised matching
function.
the problem is that to bind the types required to do this
*also* requires lookup (and it can even be recursive).
So in the process of doing all this lookup, it would be nice
to cache the results so that the 'expensive' lookup is only
done once, and after that the cached value is used.
In fact I tried that using a Hashtbl .. but because the keys
were complex, it turned out that polymorphic compare and hash
functions were actually *slower* than my nasty purely functional
lookup code.
However, I do cache the environments, and this save some
time: environments are created by a call like
build_env (parent)
which follows the chain of parents to ground, gathering
all the symbols defined in each one (resulting in a list
of hashtables). This process isn't all that slow .. the
problem is that in a purely functional system with
random symbol lookups, it has to be done once for EVERY
lookup .. not just once when you do a lookup, since as
noted above doing a lookup can spawn a hundreds of other
lookups. So caching the 'environment' in which to do the
lookups was a good way to speed up the process, without
changing the functional style of the code.
--
John Skaller <skaller at users dot sf dot net>
Felix, successor to C++: http://felix.sf.net
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: [Caml-list] Avoiding shared data
2005-10-03 13:09 ` Thomas Fischbacher
2005-10-03 14:57 ` skaller
2005-10-03 20:03 ` Ant: " Martin Chabr
@ 2005-10-05 11:14 ` Andrej Bauer
2 siblings, 0 replies; 44+ messages in thread
From: Andrej Bauer @ 2005-10-05 11:14 UTC (permalink / raw)
Cc: caml-list
Thomas Fischbacher wrote:
> He presumably wanted to see a different thing, e.g.
> automatically transforming
> let rec fac1 x =
> if x = 0
> then 1
> else x*(fac1 (x-1))
> ;;
>
> into
>
> let fac2 x =
> let rec walk so_far todo =
> if todo = 0
> then so_far
> else walk (todo*so_far) (todo-1)
> in walk 1 x
> ;;
>
> My impression is that it may indeed be possible to do something like this
> for simple applications, but that the cases that can be covered
> automatically presumably are so limited that an experienced programmer
> will usually want to attack them by going to a higher form of abstraction
> and not waste time on such things anyway.
Incidentally, I recently wrote a little piece on how to transform one
kind of recursion into another kind of recursion via
propositions-as-types http://math.andrej.com/2005/09/16/proof-hacking/
which may be of interest to some of you. I only considered a very simple
kind of recursion on natural numbers. My impression is that quite a
general form of recursion could be treated (replace natural numbers by a
well-founded type, for example).
This sort of thing is probably not immediately useful in programming
practice. But even "real" programmers should be aware of abstract
mathematical ideas because they they indirectly make them write better
programs.
Best regards,
Andrej
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: FP/IP and performance (in general) and Patterns... (Re: [Caml-list] Avoiding shared data)
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
` (2 more replies)
1 sibling, 3 replies; 44+ messages in thread
From: Oliver Bandel @ 2005-10-05 12:10 UTC (permalink / raw)
To: caml-list
On Tue, Oct 04, 2005 at 06:39:28PM -0400, Christopher A. Watford wrote:
[...]
> This list is best for asking OCaml questions and is awful for asking
> for what language is best for what, nobody agrees.
[...]
I was not asking, what language is better for soimething, or best at all.
I asked for what programming style/paradigm is best used to solve
certain problems.
As OCaml provides more than one programming paradigm, for me
it's the best language I ever had programmed in (some
other features are also fine).
So the question goes in a different direction:
How to solve problems best, if you have the possibility
do do it in different ways.
Well, every programmer can choose it's own way, but if certain areas
are well known to do them in a certain way best, it makes sense
to go that direction.
For example, I'm not really a fan of OO-programming, but when
programming GUI-software I think it would be the best choice,
and FP-programming lacks flexibility here (if not using
a DSL to create GUI-code, which then is separately compiled).
Ciao,
Oliver
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: FP/IP and performance (in general) and Patterns... (Re: [Caml-list] Avoiding shared data)
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
2 siblings, 0 replies; 44+ messages in thread
From: Jon Harrop @ 2005-10-05 13:08 UTC (permalink / raw)
To: caml-list
On Wednesday 05 October 2005 13:10, Oliver Bandel wrote:
> For example, I'm not really a fan of OO-programming, but when
> programming GUI-software I think it would be the best choice,
> and FP-programming lacks flexibility here (if not using
> a DSL to create GUI-code, which then is separately compiled).
I am finding ordinary FP perfectly adequate for GUI programming. My GUI
programming may be unorthodox, however. :-)
--
Dr Jon D Harrop, Flying Frog Consultancy Ltd.
Objective CAML for Scientists
http://www.ffconsultancy.com/products/ocaml_for_scientists
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: FP/IP and performance (in general) and Patterns... (Re: [Caml-list] Avoiding shared data)
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
2 siblings, 0 replies; 44+ messages in thread
From: skaller @ 2005-10-05 15:28 UTC (permalink / raw)
To: Oliver Bandel; +Cc: caml-list
On Wed, 2005-10-05 at 14:10 +0200, Oliver Bandel wrote:
> For example, I'm not really a fan of OO-programming, but when
> programming GUI-software I think it would be the best choice,
> and FP-programming lacks flexibility here
I contend that concurrent programming is best here.
However, I don't know: I have a tool (Felix) to explore
this, but haven't got around to actually trying the
one-thread/one-widget paradigm.
The OO solution is reactive and requires you to maintain
the whole widget state without use of the stack, thereby
discarding everything that is known about block structured
and functional programming, and going back to the bad old
days of the early 70s with a flat state space, except that
the state space is partitioned into objects.
The thread based solution control inverts this paradigm,
giving you a stack and control flow for every widget,
this is *active* or algorithmic programming. So I content
it must be better, because it not only partitions the state
space as OO does, it *also* partitions the control space,
and allows you to use all the advantages of a functional
or block structured style.
Actually, in practice, I expect a mix of the solutions
will be best. The reason is: we know a LOT about
state machines. So subparts of problems which correspond
to them can easily be programmed and reasoned about,
simply because we have lots of mature theory.
--
John Skaller <skaller at users dot sf dot net>
Felix, successor to C++: http://felix.sf.net
^ permalink raw reply [flat|nested] 44+ messages in thread
* Ant: Re: FP/IP and performance (in general) and Patterns... (Re: [Caml-list] Avoiding shared data)
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 ` Martin Chabr
2005-10-05 23:21 ` Markus Mottl
2 siblings, 1 reply; 44+ messages in thread
From: Martin Chabr @ 2005-10-05 20:52 UTC (permalink / raw)
To: Oliver Bandel; +Cc: caml-list
>From my limited experience I see it this way:
Mathematical computations, algorithms, interfacing
(complicated data conversions), text translations,
parsing, anything which can be well represented by
dataflow diagrams and where there is no changing state
==>
use FP
User interfaces, business systems, anything with
objects which have changing states and which react to
events and interact with each other ==> use OOP
Martin
--- Oliver Bandel <oliver@first.in-berlin.de> wrote:
> On Tue, Oct 04, 2005 at 06:39:28PM -0400,
> Christopher A. Watford wrote:
> [...]
> > This list is best for asking OCaml questions and
> is awful for asking
> > for what language is best for what, nobody agrees.
> [...]
>
>
> I was not asking, what language is better for
> soimething, or best at all.
> I asked for what programming style/paradigm is best
> used to solve
> certain problems.
>
> As OCaml provides more than one programming
> paradigm, for me
> it's the best language I ever had programmed in
> (some
> other features are also fine).
>
> So the question goes in a different direction:
> How to solve problems best, if you have the
> possibility
> do do it in different ways.
>
> Well, every programmer can choose it's own way, but
> if certain areas
> are well known to do them in a certain way best, it
> makes sense
> to go that direction.
>
> For example, I'm not really a fan of OO-programming,
> but when
> programming GUI-software I think it would be the
> best choice,
> and FP-programming lacks flexibility here (if not
> using
> a DSL to create GUI-code, which then is separately
> compiled).
>
> Ciao,
> Oliver
>
> _______________________________________________
> Caml-list mailing list. Subscription management:
>
http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list
> Archives: http://caml.inria.fr
> Beginner's list:
> http://groups.yahoo.com/group/ocaml_beginners
> Bug reports: http://caml.inria.fr/bin/caml-bugs
>
___________________________________________________________
Gesendet von Yahoo! Mail - Jetzt mit 1GB Speicher kostenlos - Hier anmelden: http://mail.yahoo.de
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Ant: Re: FP/IP and performance (in general) and Patterns... (Re: [Caml-list] Avoiding shared data)
2005-10-05 20:52 ` Ant: " Martin Chabr
@ 2005-10-05 23:21 ` Markus Mottl
2005-10-06 16:54 ` brogoff
0 siblings, 1 reply; 44+ messages in thread
From: Markus Mottl @ 2005-10-05 23:21 UTC (permalink / raw)
To: Martin Chabr; +Cc: Oliver Bandel, caml-list
On 10/5/05, Martin Chabr <martin_chabr@yahoo.de> wrote:
> User interfaces, business systems, anything with
> objects which have changing states and which react to
> events and interact with each other ==> use OOP
FWIW, we use OCaml for fairly large systems (> 100 KLOCs, > 1000
modules) with very complicated business logic handling high-volume
realtime events. Even though OCaml supports OOP very well, probably
much better than most mainstream languages, we do not use OOP and are
not intending to do so. Mutable records together with modules are
perfectly fine for handling changing states safely and efficiently and
are in the general case semantically more transparent than objects.
Your mileage may vary...
Regards,
Markus
--
Markus Mottl http://www.ocaml.info markus.mottl@gmail.com
^ permalink raw reply [flat|nested] 44+ messages in thread
* Re: Ant: Re: FP/IP and performance (in general) and Patterns... (Re: [Caml-list] Avoiding shared data)
2005-10-05 23:21 ` Markus Mottl
@ 2005-10-06 16:54 ` brogoff
0 siblings, 0 replies; 44+ messages in thread
From: brogoff @ 2005-10-06 16:54 UTC (permalink / raw)
To: caml-list
On Wed, 5 Oct 2005, Markus Mottl wrote:
> FWIW, we use OCaml for fairly large systems (> 100 KLOCs, > 1000
> modules) with very complicated business logic handling high-volume
> realtime events. Even though OCaml supports OOP very well, probably
> much better than most mainstream languages, we do not use OOP and are
> not intending to do so. Mutable records together with modules are
> perfectly fine for handling changing states safely and efficiently and
> are in the general case semantically more transparent than objects.
> Your mileage may vary...
I don't disagree with anything above, but thought I'd mention that OCaml
classes can be used as more polymorphic records (giving up pattern matching
and some performance), without using the late-binding/open-recursion aspect
which is the sine qua non of OOP.
-- Brian
^ permalink raw reply [flat|nested] 44+ messages in thread
* Ant: Re: [Caml-list] Avoiding shared data
[not found] <Pine.LNX.4.63.0509251653340.9226@localhost.localdomain>
@ 2005-09-26 21:29 ` Martin Chabr
0 siblings, 0 replies; 44+ messages in thread
From: Martin Chabr @ 2005-09-26 21:29 UTC (permalink / raw)
To: Brian Hurt; +Cc: caml-list
Hello Brian,
thank you for the whole lot of useful tips and nice
explanations. It is immediately clear to me how to
copy a record and a tuple, but I will need some time
to think about your suggestions using a map.
Intuitively I feel that it needs a method to create
non-shared data structures in the first place, so that
no copying whatsoever is needed.
Regards,
Martin
--- Brian Hurt <bhurt@spnz.org> schrieb:
>
>
> On Sun, 25 Sep 2005, Martin Chabr wrote:
>
> > Working with non-shared data structures in OCaml
> > Deep copy of OCaml structures, marshaling
> > ================================================
> >
> > Dear group members,
> >
> > I need to process arrays of pairs of integers and
> > records ((int * record) array) in which all
> elements
> > must be updated individually, which means that
> > unshared data structures must be used. For arrays
> of
> > arrays I can produce unshared data by using the
> > library functions Array.copy and Array.append to
> > append the individual arrays into the embedding
> array.
> > It works, the low level arrays can be updated
> > individually. But I cannot use the same scheme to
> the
> > array of the (int * record) structures, because I
> do
> > not know how to copy these structures to dissolve
> the
> > sharing. I do not even know how to copy records.
> It
> > seems to me that this problem occurs always when I
> > want to produce an array of data with a fixed
> > structure automatically (rather than entering the
> > array [| ... |] by hand at the top level
> interpreter
> > using constants only). How can I produce
> completely
> > unshared structures?
>
> First of all, you can copy a structure easily enough
> using the with key
> word. Say you have:
>
> type my_struct = {
> foo: int;
> bar: float;
> baz: string;
> }
>
> You can write a copy function just like:
>
> let copy_my_struct x = { x with foo = x.foo };;
>
> In this case, the "with" construct says "create a
> new structure with the
> same elements as the old structure, except give the
> foo member this new
> value (which in this case just happens to be the
> same value as the old
> value)". Unfortunately you have to specify at least
> one new value to use
> the with construct, even if it doesn't get a new
> value. This is
> especially usefull if there are other value you want
> to copy, for example,
> you probably want to write:
>
> let copy_my_struct x = { x with baz = String.copy
> x.baz }
>
> As this doesn't just create a new copy of the
> structure, it also creates a
> new copy of the string as well (foo and bar get
> whatever values the
> original structure had).
>
> I can create a new tuple just by breaking the old
> tuple apart and putting
> it back together again. For all two element tuples,
> I can create a new
> copy of them just by going:
>
> let copy_tuple (a,b) = a,b
>
> This function, given a tuple of two elements,
> creates a new tuple with the
> same two elements.
>
> The easiest way to create a new list from old values
> is to just use the
> map function. The output list type of List.map can
> be the same type as
> the input list. This is really usefull- imagine
> that I want to add 1 each
> to a list of floats, I can just write:
>
> List.map (fun i -> i + 1) lst
>
> So, to answer you specific question, say I have an
> (int * my_struct) list
> (where t is the structure I defined above). The
> function to create a
> whole new copy of this list (assuming I've written
> copy_t like I did
> above) is just:
>
> let copy_list lst = List.map (fun (i,s) -> i,
> (copy_my_struct s)) lst
>
> Notice that I made copy_tuple an anonymous (unnamed)
> function there. With
> a couple of more tricks I can fit the whole thing on
> one line:
>
> let cplst = List.map (fun (i,s) -> i, {s with baz =
> String.copy s.baz})
>
> Which is nice for bragging rights, but I kind of
> like the more unpacked
> version.
>
> Now, I'm going to jump from the question you asked
> to the question you
> didn't ask, and make a big assumption along the way.
> I'd bet dollars to
> donuts that you really don't want to be using either
> lists or array- you
> really want to be using a map. Let me guess: you've
> written a function
> like:
>
> let rec find i lst = (* find element i in list lst)
> match lst with
> | (j, s) :: t ->
> if i == j then
> s
> else
> find i t
> | [] -> raise Not_found
>
> and are calling it a lot (or rewritting it a lot).
> If this is the case,
> then what you really want to be using is a map, not
> a list or an array.
> You can do this with the following code:
>
> module Int = struct
> type t = int
> let compare (x: int) y =
> if x < y then
> -1
> else if x > y then
> 1
> else
> 0
> end;;
>
> module IntMap = Map.Make(Int);;
>
> Now you can just keep your structures in a my_struct
> IntMap.t. The find
> function is now:
> let find i lst = (* lst is a IntMap, not a list *)
> IntMap.find i lst
> ;;
>
> The big difference here is that IntMap.find is O(log
> N) cost, while the
> list-based find I wrote above is O(N) cost. What
> this means is that if
> the list is 1000 elements long, the list-based find
> will have to do (on
> aveage) about 500 steps of processing to find the
> answer- it has to walk
> halfway down the list. The IntMap.find function,
> however, only has to do
> about 10 steps on average to find the answer- it's
> literally 50 times
> faster to do the IntMap.find in this case than the
> list-based find. If
> we're dealing with a million elements, the
> list-based find will take
> 500,000 steps to find the answer on average, the
> IntMap.find only 20, for
> an incredible speed up of 25,000 times.
>
> Note that IntMap has a map function as well- so I
> can steal the exact same
> trick to copy it (but note that I don't have to
> allocate the new tuples):
>
> let copy_list lst = (* list is an IntMap, not a list
> *)
> IntMap.map copy_my_struct lst
> ;;
>
> If you actually want the associated integers as
> well, use mapi instead of
> map.
>
> Note that O(log N) vr.s O(N) thing applies to
> updates as well. Let's say
>
=== message truncated ===
___________________________________________________________
Was denken Sie über E-Mail? Wir hören auf Ihre Meinung: http://surveylink.yahoo.com/wix/p0379378.aspx
^ permalink raw reply [flat|nested] 44+ messages in thread
end of thread, other threads:[~2005-10-06 16:54 UTC | newest]
Thread overview: 44+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2005-09-25 21:32 Avoiding shared data 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
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
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).