caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* [Caml-list] "List.index" or "List.unique" functions?
@ 2004-04-30 17:54 Rahul Siddharthan
  2004-04-30 18:51 ` Martin Jambon
                   ` (3 more replies)
  0 siblings, 4 replies; 27+ messages in thread
From: Rahul Siddharthan @ 2004-04-30 17:54 UTC (permalink / raw)
  To: caml-list

I just discovered OCaml a week or so ago, and it really seems to be
the "holy grail" -- more concise and elegant that python, almost as
fast as C.  I wish I'd known of it a year ago.  Now I just need to get
used to the functional way of thinking...

I have a question: suppose I have a list l1, and I want to create a new
list l2 with only one copy of any repeated members of the first list
(eg, l1=[1;2;3;4;3;4;5;6;5] -> l2=[1;2;3;4;5;6])

In python, I can define a function to do this quite concisely, eg:

unique = lambda l: [l[n] for n in range(len(l)) if l.index(l[n])==n]

How do I do it in OCaml?  Are there functions equivalent to index
(return the position of the first matching element in the list) and
range (range n = [0;1;...;n-1]), or is there a cleaner way to do it?
The best I can come up with is:

let unique l = 
  let range n = 
    let rec rangen n lacc =
      if n<0 then lacc else rangen (n-1) (n::lacc)
    in rangen (n-1) []
  in
  let index a l =
    let rec indexn a l n =
      if n==(List.length l) then -1
      else if (List.nth l n) =a then n
      else indexn a l (n+1)
    in indexn a l 0
  in 
  List.map (fun n -> List.nth l n) (List.filter 
                                      (fun n -> n=(index (List.nth l n) l))   
                                      (range (List.length l)));;

(it would be more concise if range and index already exist, but even
then, the last line looks rather ugly to me...)

Thanks

Rahul

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Caml-list] "List.index" or "List.unique" functions?
  2004-04-30 17:54 [Caml-list] "List.index" or "List.unique" functions? Rahul Siddharthan
@ 2004-04-30 18:51 ` Martin Jambon
  2004-04-30 19:01 ` Benjamin Geer
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 27+ messages in thread
From: Martin Jambon @ 2004-04-30 18:51 UTC (permalink / raw)
  To: Rahul Siddharthan; +Cc: caml-list

On Fri, 30 Apr 2004, Rahul Siddharthan wrote:

> I just discovered OCaml a week or so ago, and it really seems to be
> the "holy grail" -- more concise and elegant that python, almost as
> fast as C.  I wish I'd known of it a year ago.  Now I just need to get
> used to the functional way of thinking...
>
> I have a question: suppose I have a list l1, and I want to create a new
> list l2 with only one copy of any repeated members of the first list
> (eg, l1=[1;2;3;4;3;4;5;6;5] -> l2=[1;2;3;4;5;6])

1) Naive O(n^2) solution:
let rec unique = function
    [] -> []
  | hd :: tl ->
      if List.mem hd tl then unique tl
      else hd :: unique tl

The result is not sorted.


2) With a hash table you can get something quite efficient (O(n)) and not
too difficult to write:

let unique l =
  let tbl = Hashtbl.create 10 in
  List.iter (fun i -> Hashtbl.replace tbl i ()) l;
  Hashtbl.fold (fun key data accu -> key :: accu) tbl []

The result is not sorted.
You can replace "10" with "List.length l" if really you don't have any
idea of the initial size of the table and want to avoid multiple resizings
of the table.

"fold" functions (List.fold_left, List.fold_right, Hashtbl.fold,
Array.fold_left...) are very useful, and are most of the time more
appropriate than imperative loops ("for" and "while").


3) With sort/simplify (O(n log n)) (I expect it to be much less
efficient than 2)):

let unique l =
  let rec simplify last l =
    match l with
	[] -> [last]
      | hd :: tl ->
	  if hd = last then
	    simplify last tl
	  else
	    last :: simplify hd tl in
  match List.sort compare l with
      [] -> []
    | hd :: tl ->
	simplify hd tl


Martin

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Caml-list] "List.index" or "List.unique" functions?
  2004-04-30 17:54 [Caml-list] "List.index" or "List.unique" functions? Rahul Siddharthan
  2004-04-30 18:51 ` Martin Jambon
@ 2004-04-30 19:01 ` Benjamin Geer
  2004-04-30 19:07   ` Thanks " Rahul Siddharthan
  2004-04-30 19:08 ` Karl Zilles
  2004-05-01 10:03 ` [Caml-list] "List.index" or "List.unique" functions? Richard Jones
  3 siblings, 1 reply; 27+ messages in thread
From: Benjamin Geer @ 2004-04-30 19:01 UTC (permalink / raw)
  To: Rahul Siddharthan; +Cc: caml-list

Rahul Siddharthan wrote:
> I have a question: suppose I have a list l1, and I want to create a new
> list l2 with only one copy of any repeated members of the first list
> (eg, l1=[1;2;3;4;3;4;5;6;5] -> l2=[1;2;3;4;5;6])

Here's one way:

let unique ls =
   let uniq_aux new_ls old_elem =
     match new_ls with
       | [] -> [ old_elem ]
       | hd :: tl when hd = old_elem -> new_ls
       | _ -> old_elem :: new_ls
   in
   let sorted = List.sort compare ls in
     List.rev (List.fold_left uniq_aux [] sorted) ;;

Ben

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Thanks Re: [Caml-list] "List.index" or "List.unique" functions?
  2004-04-30 19:01 ` Benjamin Geer
@ 2004-04-30 19:07   ` Rahul Siddharthan
  0 siblings, 0 replies; 27+ messages in thread
From: Rahul Siddharthan @ 2004-04-30 19:07 UTC (permalink / raw)
  To: caml-list

Thanks to all who replied, on- and off-list.  I got many nice answers.

Thanks also for those who let me know about the ocaml-beginners list.
It wasn't listed on www.ocaml.org, which I didn't realise was an 
unofficial page. 

Rahul

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Caml-list] "List.index" or "List.unique" functions?
  2004-04-30 17:54 [Caml-list] "List.index" or "List.unique" functions? Rahul Siddharthan
  2004-04-30 18:51 ` Martin Jambon
  2004-04-30 19:01 ` Benjamin Geer
@ 2004-04-30 19:08 ` Karl Zilles
  2004-04-30 19:29   ` Matthieu Sozeau
                     ` (2 more replies)
  2004-05-01 10:03 ` [Caml-list] "List.index" or "List.unique" functions? Richard Jones
  3 siblings, 3 replies; 27+ messages in thread
From: Karl Zilles @ 2004-04-30 19:08 UTC (permalink / raw)
  To: Rahul Siddharthan; +Cc: caml-list

Rahul Siddharthan wrote:
> I have a question: suppose I have a list l1, and I want to create a new
> list l2 with only one copy of any repeated members of the first list
> (eg, l1=[1;2;3;4;3;4;5;6;5] -> l2=[1;2;3;4;5;6])

let unique l = List.rev (List.fold_left (fun results x -> if 
List.mem x 		results then results else x::results) [] l);;

unique [1;2;3;4;3;4;5;6;5];;
- : int list = [1; 2; 3; 4; 5; 6]

List.rev is not tail recursive, so you wouldn't want to use this 
function on industrial size lists.

You might want to check out the ocaml_beginners@yahoogroups.com mailing 
list.  That is a good place to ask questions like this.

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Caml-list] "List.index" or "List.unique" functions?
  2004-04-30 19:08 ` Karl Zilles
@ 2004-04-30 19:29   ` Matthieu Sozeau
  2004-04-30 20:01     ` Karl Zilles
  2004-04-30 20:05   ` Remi Vanicat
  2004-05-01  1:59   ` [Caml-list] List.rev skaller
  2 siblings, 1 reply; 27+ messages in thread
From: Matthieu Sozeau @ 2004-04-30 19:29 UTC (permalink / raw)
  To: caml-list

On Fri, Apr 30, 2004 at 12:08:56PM -0700, Karl Zilles wrote:
> List.rev is not tail recursive, so you wouldn't want to use this 
> function on industrial size lists.

List.rev and List.rev_map are tail recursive, unlike map. It can be
really benefical sometimes to use an accumulator in a recursive
function and reverse it at the end (it certainly wouldn't if List.rev
was not tail recursive).
-- 
It's a small world, but I wouldn't want to have to paint it.
		-- Steven Wright

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Caml-list] "List.index" or "List.unique" functions?
  2004-04-30 19:29   ` Matthieu Sozeau
@ 2004-04-30 20:01     ` Karl Zilles
  0 siblings, 0 replies; 27+ messages in thread
From: Karl Zilles @ 2004-04-30 20:01 UTC (permalink / raw)
  To: Matthieu Sozeau; +Cc: caml-list

Matthieu Sozeau wrote:
> On Fri, Apr 30, 2004 at 12:08:56PM -0700, Karl Zilles wrote:
> 
>>List.rev is not tail recursive, so you wouldn't want to use this 
>>function on industrial size lists.
> 
> 
> List.rev and List.rev_map are tail recursive, unlike map. It can be
> really benefical sometimes to use an accumulator in a recursive
> function and reverse it at the end (it certainly wouldn't if List.rev
> was not tail recursive).

You're right.  Not sure how that got into my head.  Thanks for the 
correction.

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Caml-list] "List.index" or "List.unique" functions?
  2004-04-30 19:08 ` Karl Zilles
  2004-04-30 19:29   ` Matthieu Sozeau
@ 2004-04-30 20:05   ` Remi Vanicat
  2004-04-30 20:47     ` JM Nunes
  2004-05-01  1:59   ` [Caml-list] List.rev skaller
  2 siblings, 1 reply; 27+ messages in thread
From: Remi Vanicat @ 2004-04-30 20:05 UTC (permalink / raw)
  To: caml-list

Karl Zilles <zilles@1969.ws> writes:

> Rahul Siddharthan wrote:
>> I have a question: suppose I have a list l1, and I want to create a new
>> list l2 with only one copy of any repeated members of the first list
>> (eg, l1=[1;2;3;4;3;4;5;6;5] -> l2=[1;2;3;4;5;6])
>
> let unique l = List.rev (List.fold_left (fun results x -> if List.mem
> x 		results then results else x::results) [] l);;
>
> unique [1;2;3;4;3;4;5;6;5];;
> - : int list = [1; 2; 3; 4; 5; 6]
>
> List.rev is not tail recursive, so you wouldn't want to use this
> function on industrial size lists.

List.rev is tail recursive...

[...]


-- 
Rémi Vanicat

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Caml-list] "List.index" or "List.unique" functions?
  2004-04-30 20:05   ` Remi Vanicat
@ 2004-04-30 20:47     ` JM Nunes
  2004-04-30 20:58       ` Karl Zilles
  0 siblings, 1 reply; 27+ messages in thread
From: JM Nunes @ 2004-04-30 20:47 UTC (permalink / raw)
  To: caml-list

Note that List.rev is not being useful in this case. 

> let unique l = List.rev (List.fold_left (fun results x -> if List.mem
> x 		results then results else x::results) [] l);;
>
> unique [1;2;3;4;3;4;5;6;5];;
> - : int list = [1; 2; 3; 4; 5; 6]

# unique [7;1;2;3;4;3;4;5;6;5];;
- : int list = [7; 1; 2; 3; 4; 5; 6]

For sorting List.sort or other must be used.


-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Caml-list] "List.index" or "List.unique" functions?
  2004-04-30 20:47     ` JM Nunes
@ 2004-04-30 20:58       ` Karl Zilles
  0 siblings, 0 replies; 27+ messages in thread
From: Karl Zilles @ 2004-04-30 20:58 UTC (permalink / raw)
  To: JM Nunes; +Cc: caml-list

JM Nunes wrote:

> Note that List.rev is not being useful in this case. 

See below:

> 
>>let unique l = List.rev (List.fold_left (fun results x -> if List.mem
>>x 		results then results else x::results) [] l);;
>>
>>unique [1;2;3;4;3;4;5;6;5];;
>>- : int list = [1; 2; 3; 4; 5; 6]
> 
> 
> # unique [7;1;2;3;4;3;4;5;6;5];;
> - : int list = [7; 1; 2; 3; 4; 5; 6]

This is the correct output.

> 
> For sorting List.sort or other must be used.

I think what you're missing is that he's not actually looking to sort 
the list.  His python function was order preserving, as is my ocaml 
version.   His test case could have been chosen more carefully to 
demonstrate that.

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 27+ messages in thread

* [Caml-list] List.rev
  2004-04-30 19:08 ` Karl Zilles
  2004-04-30 19:29   ` Matthieu Sozeau
  2004-04-30 20:05   ` Remi Vanicat
@ 2004-05-01  1:59   ` skaller
  2004-05-01  4:18     ` Jon Harrop
                       ` (2 more replies)
  2 siblings, 3 replies; 27+ messages in thread
From: skaller @ 2004-05-01  1:59 UTC (permalink / raw)
  To: caml-list

On Sat, 2004-05-01 at 05:08, Karl Zilles wrote:
> Rahul Siddharthan wrote:

> List.rev is not tail recursive, so you wouldn't want to use this 
> function on industrial size lists.

But it should be. Why isn't it???

let rev lst = let r = ref [] in
  let rec aux lst = match lst with
  | [] -> !r
  | h::t -> r:= h :: !r; aux t
in aux lst

BTW: documentation that says a function is 'tail recursive'
is misguided. That's an implementation detail of no
possible use to a user of the function. The user may
benefit from knowing the complexity of the function
in terms of speed and auxilliary storage required.

-- 
John Skaller, mailto:skaller@users.sf.net
voice: 061-2-9660-0850, 
snail: PO BOX 401 Glebe NSW 2037 Australia
Checkout the Felix programming language http://felix.sf.net



-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Caml-list] List.rev
  2004-05-01  1:59   ` [Caml-list] List.rev skaller
@ 2004-05-01  4:18     ` Jon Harrop
  2004-05-01  4:38     ` brogoff
  2004-05-01 16:41     ` John Goerzen
  2 siblings, 0 replies; 27+ messages in thread
From: Jon Harrop @ 2004-05-01  4:18 UTC (permalink / raw)
  To: caml-list

On Saturday 01 May 2004 02:59, skaller wrote:
> > List.rev is not tail recursive, so you wouldn't want to use this
> > function on industrial size lists.
>
> But it should be. Why isn't it???

I'm not sure that it isn't already tail-recursive. Doesn't the second argument 
in rev_append act as an accumulator?

> let rev lst = let r = ref [] in
>   let rec aux lst = match lst with
>
>   | [] -> !r
>   | h::t -> r:= h :: !r; aux t

let rev l = fold_left (fun t h -> h::t) [] l

=:-p

> BTW: documentation that says a function is 'tail recursive'
> is misguided. That's an implementation detail of no
> possible use to a user of the function. The user may
> benefit from knowing the complexity of the function
> in terms of speed and auxilliary storage required.

As "tail recursive" typically means less stack storage and more heap storage 
instead of the reverse, it is useful to a user and it does pertain to the 
complexity (although it obviously doesn't quantify the complexity of the heap 
storage).

Cheers,
Jon.

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Caml-list] List.rev
  2004-05-01  1:59   ` [Caml-list] List.rev skaller
  2004-05-01  4:18     ` Jon Harrop
@ 2004-05-01  4:38     ` brogoff
  2004-05-01  5:12       ` skaller
  2004-05-01 16:41     ` John Goerzen
  2 siblings, 1 reply; 27+ messages in thread
From: brogoff @ 2004-05-01  4:38 UTC (permalink / raw)
  To: skaller; +Cc: caml-list

On Fri, 1 May 2004, skaller wrote:
> BTW: documentation that says a function is 'tail recursive'
> is misguided. That's an implementation detail of no
> possible use to a user of the function. The user may
> benefit from knowing the complexity of the function
> in terms of speed and auxilliary storage required.

You couldn't be more wrong. When your program crashes because you've blown
stack and you're embarassed as all hell (you never expected the user to run
with *that* big of an input) you remember that documentation and curse your
own carelessness, rather than the OCaml team.

Since Ocaml optimizes tail calls, that info *is* about auxiliary storage.

On the same point, it would be a good thing if OCaml had a better solution
to these "tail recursion modulo cons" issues than writing set_cdr using
Obj functions. Better means "in the language" here; I'm aware that various
libraries have implemented the set_cdr approach.

There's only a handful of things that bug me about the OCaml language, and
this  makes the list. I'd append it to the list, but it might raise an
exception ;-).


-- Brian

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Caml-list] List.rev
  2004-05-01  4:38     ` brogoff
@ 2004-05-01  5:12       ` skaller
  2004-05-01  7:08         ` William Lovas
  2004-05-01 10:07         ` Richard Jones
  0 siblings, 2 replies; 27+ messages in thread
From: skaller @ 2004-05-01  5:12 UTC (permalink / raw)
  To: brogoff; +Cc: caml-list

On Sat, 2004-05-01 at 14:38, brogoff@speakeasy.net wrote:
> On Fri, 1 May 2004, skaller wrote:
> > BTW: documentation that says a function is 'tail recursive'
> > is misguided. That's an implementation detail of no
> > possible use to a user of the function. The user may
> > benefit from knowing the complexity of the function
> > in terms of speed and auxilliary storage required.
> 
> You couldn't be more wrong.

Due respect but I am quite correct and provably so.

Tail-rec is a property of an actual function implementation.

The term has no meaning without exhibiting implementation
code, and it is usual for libraries to quite pointedly
NOT do that: instead the behaviour is specified in
terms of input and output of the function, and also
side effects in terms of time and storage requirements
are sometimes thrown in for more detail.

Saying tail-rec is suggestive only if you have
an implementation in your minds-eye.

It is good the documentation says the function
is tail-rec, this is better than no performance
information

BUT IT IS STILL NOT A NORMATIVE SPECIFICATION.


-- 
John Skaller, mailto:skaller@users.sf.net
voice: 061-2-9660-0850, 
snail: PO BOX 401 Glebe NSW 2037 Australia
Checkout the Felix programming language http://felix.sf.net



-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Caml-list] List.rev
  2004-05-01  5:12       ` skaller
@ 2004-05-01  7:08         ` William Lovas
  2004-05-01  8:10           ` skaller
  2004-05-01 10:07         ` Richard Jones
  1 sibling, 1 reply; 27+ messages in thread
From: William Lovas @ 2004-05-01  7:08 UTC (permalink / raw)
  To: caml-list

On Sat, May 01, 2004 at 03:12:57PM +1000, skaller wrote:
> The term has no meaning without exhibiting implementation
> code, and it is usual for libraries to quite pointedly
> NOT do that: instead the behaviour is specified in
> terms of input and output of the function, and also
> side effects in terms of time and storage requirements
> are sometimes thrown in for more detail.

In many functional languages, O'Caml included, it's assumed that tail calls
are optimized to jumps, so that tail recursive functions do not allocate
any stack space for each recursive call.  (I believe in Scheme this is even
included in the language specification.)

With that in mind, you can read "This function is not tail recursive" as a
behavioral specification, "This function might terminate abnormally due to
stack overflow" -- and that's a useful side effect to document.

William

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Caml-list] List.rev
  2004-05-01  7:08         ` William Lovas
@ 2004-05-01  8:10           ` skaller
  2004-05-01  8:32             ` Jon Harrop
  2004-05-02 12:07             ` Andreas Rossberg
  0 siblings, 2 replies; 27+ messages in thread
From: skaller @ 2004-05-01  8:10 UTC (permalink / raw)
  To: William Lovas; +Cc: caml-list

On Sat, 2004-05-01 at 17:08, William Lovas wrote:

> In many functional languages, O'Caml included, it's assumed that tail calls
> are optimized to jumps, so that tail recursive functions do not allocate
> any stack space for each recursive call.  (I believe in Scheme this is even
> included in the language specification.)
> 
> With that in mind, you can read "This function is not tail recursive" as a
> behavioral specification, "This function might terminate abnormally due to
> stack overflow" -- and that's a useful side effect to document.

Indeed. I know that. But it is suboptimal.
There are better ways to write specifications
that (a) refer to an implementation that isn't exhibited
and (b) assume tail-rec implies no stack allocation

The first is called 'ill formed formula', and
the second is called 'unwarranted assumption'.

So the spec is (a) meaningless gibberish 
and (b) even if the implementation were exhibited
it says nothing about the performance.

Yet it is easy enough to say 

O(n) time and O(1) stack

and mean that this is a *requirement* on the implementation
and a guarrantee to the programmer.

That is the intent, why not say it?


-- 
John Skaller, mailto:skaller@users.sf.net
voice: 061-2-9660-0850, 
snail: PO BOX 401 Glebe NSW 2037 Australia
Checkout the Felix programming language http://felix.sf.net



-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Caml-list] List.rev
  2004-05-01  8:10           ` skaller
@ 2004-05-01  8:32             ` Jon Harrop
  2004-05-01  9:24               ` skaller
  2004-05-02 12:07             ` Andreas Rossberg
  1 sibling, 1 reply; 27+ messages in thread
From: Jon Harrop @ 2004-05-01  8:32 UTC (permalink / raw)
  To: caml-list

On Saturday 01 May 2004 09:10, skaller wrote:
> Yet it is easy enough to say
>
> O(n) time and O(1) stack

O(n) heap

But why restrict yourself to asymptotic complexities... ;-)

Cheers,
Jon.

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Caml-list] List.rev
  2004-05-01  8:32             ` Jon Harrop
@ 2004-05-01  9:24               ` skaller
  0 siblings, 0 replies; 27+ messages in thread
From: skaller @ 2004-05-01  9:24 UTC (permalink / raw)
  To: Jon Harrop; +Cc: caml-list

On Sat, 2004-05-01 at 18:32, Jon Harrop wrote:
> On Saturday 01 May 2004 09:10, skaller wrote:
> > Yet it is easy enough to say
> >
> > O(n) time and O(1) stack
> 
> O(n) heap

Well, the output requires O(n) heap by nature of
the result..

> But why restrict yourself to asymptotic complexities... ;-)

Good question. one reason is that it's hard to do better
in a specification: you can't very well say 'this takes
1 second' :-)

However, perhaps you can say something for small n.

Usually this is a QOI issue. QOI = Quality of Implementation.
Meaning "not an issue for standardisation". QOI is important
of course -- we use Ocaml because of its high performance.

-- 
John Skaller, mailto:skaller@users.sf.net
voice: 061-2-9660-0850, 
snail: PO BOX 401 Glebe NSW 2037 Australia
Checkout the Felix programming language http://felix.sf.net



-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Caml-list] "List.index" or "List.unique" functions?
  2004-04-30 17:54 [Caml-list] "List.index" or "List.unique" functions? Rahul Siddharthan
                   ` (2 preceding siblings ...)
  2004-04-30 19:08 ` Karl Zilles
@ 2004-05-01 10:03 ` Richard Jones
  3 siblings, 0 replies; 27+ messages in thread
From: Richard Jones @ 2004-05-01 10:03 UTC (permalink / raw)
  Cc: caml-list

On Fri, Apr 30, 2004 at 01:54:29PM -0400, Rahul Siddharthan wrote:
> I have a question: suppose I have a list l1, and I want to create a new
> list l2 with only one copy of any repeated members of the first list
> (eg, l1=[1;2;3;4;3;4;5;6;5] -> l2=[1;2;3;4;5;6])

This is actually another function which could be usefully added to
the standard library, along with:

frequency : 'a list -> (int * 'a) list     (requires input list to be sorted)

and group_by, defined by Isaac Trotts here:

http://groups.yahoo.com/group/ocaml_beginners/message/1556

Rich.

-- 
Richard Jones. http://www.annexia.org/ http://www.j-london.com/
Merjis Ltd. http://www.merjis.com/ - improving website return on investment
http://www.YouUnlimited.co.uk/ - management courses

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Caml-list] List.rev
  2004-05-01  5:12       ` skaller
  2004-05-01  7:08         ` William Lovas
@ 2004-05-01 10:07         ` Richard Jones
  2004-05-01 10:09           ` Nicolas Cannasse
  2004-05-01 10:32           ` Jon Harrop
  1 sibling, 2 replies; 27+ messages in thread
From: Richard Jones @ 2004-05-01 10:07 UTC (permalink / raw)
  Cc: caml-list

Are there automatic ways to transform non-tail-recursive functions
into tail-recursive ones?

Rich.

-- 
Richard Jones. http://www.annexia.org/ http://www.j-london.com/
Merjis Ltd. http://www.merjis.com/ - improving website return on investment
MAKE+ is a sane replacement for GNU autoconf/automake. One script compiles,
RPMs, pkgs etc. Linux, BSD, Solaris. http://www.annexia.org/freeware/makeplus/

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Caml-list] List.rev
  2004-05-01 10:07         ` Richard Jones
@ 2004-05-01 10:09           ` Nicolas Cannasse
  2004-05-02 16:04             ` Brian Hurt
  2004-05-01 10:32           ` Jon Harrop
  1 sibling, 1 reply; 27+ messages in thread
From: Nicolas Cannasse @ 2004-05-01 10:09 UTC (permalink / raw)
  To: Richard Jones; +Cc: caml-list

> Are there automatic ways to transform non-tail-recursive functions
> into tail-recursive ones?
>
> Rich.

You can have a look at ExtLib sources. We provide tail-recursive
implementations for each List operations (with same "little o" complexity).

Regards,
Nicolas Cannasse

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Caml-list] List.rev
  2004-05-01 10:07         ` Richard Jones
  2004-05-01 10:09           ` Nicolas Cannasse
@ 2004-05-01 10:32           ` Jon Harrop
  1 sibling, 0 replies; 27+ messages in thread
From: Jon Harrop @ 2004-05-01 10:32 UTC (permalink / raw)
  To: caml-list

On Saturday 01 May 2004 11:07, Richard Jones wrote:
> Are there automatic ways to transform non-tail-recursive functions
> into tail-recursive ones?

Dunno - are we allowed to use IFS's student algorithm? ;-)

Cheers,
Jon.

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Caml-list] List.rev
  2004-05-01  1:59   ` [Caml-list] List.rev skaller
  2004-05-01  4:18     ` Jon Harrop
  2004-05-01  4:38     ` brogoff
@ 2004-05-01 16:41     ` John Goerzen
  2004-05-01 19:11       ` skaller
  2 siblings, 1 reply; 27+ messages in thread
From: John Goerzen @ 2004-05-01 16:41 UTC (permalink / raw)
  To: skaller; +Cc: caml-list

On Sat, May 01, 2004 at 11:59:10AM +1000, skaller wrote:
> BTW: documentation that says a function is 'tail recursive'
> is misguided. That's an implementation detail of no
> possible use to a user of the function. The user may
> benefit from knowing the complexity of the function
> in terms of speed and auxilliary storage required.

That wrong.  I really want to know whether or not I'm going to get a
stack overflow from using a function on a large list.

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Caml-list] List.rev
  2004-05-01 16:41     ` John Goerzen
@ 2004-05-01 19:11       ` skaller
  0 siblings, 0 replies; 27+ messages in thread
From: skaller @ 2004-05-01 19:11 UTC (permalink / raw)
  To: John Goerzen; +Cc: caml-list

On Sun, 2004-05-02 at 02:41, John Goerzen wrote:
> On Sat, May 01, 2004 at 11:59:10AM +1000, skaller wrote:
> > BTW: documentation that says a function is 'tail recursive'
> > is misguided. That's an implementation detail of no
> > possible use to a user of the function. The user may
> > benefit from knowing the complexity of the function
> > in terms of speed and auxilliary storage required.
> 
> That wrong.  I really want to know whether or not I'm going to get a
> stack overflow from using a function on a large list.

Sigh. I agree. You want to know that. And saying
'tail-rec' DOES NOT TELL YOU. Saying O(1) stack does.
So I'd like to see those comments changed to actually
describe behaviour in abstract terms, rather than
just being a loose hint about the possible implementation,
leaving you to guess what the implication is.

-- 
John Skaller, mailto:skaller@users.sf.net
voice: 061-2-9660-0850, 
snail: PO BOX 401 Glebe NSW 2037 Australia
Checkout the Felix programming language http://felix.sf.net



-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Caml-list] List.rev
  2004-05-01  8:10           ` skaller
  2004-05-01  8:32             ` Jon Harrop
@ 2004-05-02 12:07             ` Andreas Rossberg
  2004-05-02 13:29               ` skaller
  1 sibling, 1 reply; 27+ messages in thread
From: Andreas Rossberg @ 2004-05-02 12:07 UTC (permalink / raw)
  To: caml-list

skaller <skaller@users.sourceforge.net> wrote:
>
> There are better ways to write specifications
> that (a) refer to an implementation that isn't exhibited
> and (b) assume tail-rec implies no stack allocation
>
> The first is called 'ill formed formula', and
> the second is called 'unwarranted assumption'.
>
> So the spec is (a) meaningless gibberish
> and (b) even if the implementation were exhibited
> it says nothing about the performance.
>
> Yet it is easy enough to say
>
> O(n) time and O(1) stack

Sorry, but isn't talking about a stack even less meaningful
implementation-driven "gibberish"? Usually, a functional language definition
does not mention anything like a stack. In fact, some major FP
implementations don't even use a stack.

Tail recursion at least is a clear syntactic property that can be defined
without referring to implementation techniques. That a tail-recursive
function uses constant space is then a well-understood QOI issue. No serious
FP implementation would dare not to meet this criterion.

Cheers,

  - Andreas

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Caml-list] List.rev
  2004-05-02 12:07             ` Andreas Rossberg
@ 2004-05-02 13:29               ` skaller
  0 siblings, 0 replies; 27+ messages in thread
From: skaller @ 2004-05-02 13:29 UTC (permalink / raw)
  To: Andreas Rossberg; +Cc: caml-list

On Sun, 2004-05-02 at 22:07, Andreas Rossberg wrote:
> > Yet it is easy enough to say
> >
> > O(n) time and O(1) stack
> 
> Sorry, but isn't talking about a stack even less meaningful
> implementation-driven "gibberish"? 

That depends on the conformance model. One can certainly
speak of auxilliary storage requirements. In C++, one can
be definite about STL heap storage (because the store
is obtained by definite calls to an allocator).

> Usually, a functional language definition
> does not mention anything like a stack. 

A purely semantic definition may well not.
Such a definition is generally considered inadequate
for a library precisely because it doesn't include
performance requirements.

> In fact, some major FP
> implementations don't even use a stack.

Indeed .. Felix doesn't use the machine stack for 
procedure calls, its incompatible with high speed
context switching of control inverted algorithms 
on a typical Unix box.

However, Ocaml does, and, the distinction between heap
and stack is actually quite important to many clients:
many systems have a lot of potential heap, but only limited
stack. That doesn't mean distinguishing auxilliary heap
and stack is the right thing to do. I think it might be,
but I don't know, and there is a value judgement involved
deciding how much freedom an implementor should have.

It isn't necessary to specify performance: but I do believe
there is a consensus to do so. Certainly that belief
is *firmly* held in the C++ world now, since STL introduced
the idea to the committee that such requirements were an
integral part of a specification.

[There is actually a story here: there was concern that
the requirements on STL Sort were so high that NO known
implementation could meet them bar one: the one Stepanov
provided, which was subject to a Patent held by HP.
HP was asked to relinquish its intellectual property rights
and did.]

So, I'm not desiring to force my view on what conformance
model should be used, and how tight the specs are,
only that if specs are given, they be normative
well formed coherent requirements.

Its quite possible to *define* the term 'tail-rec'
in the library preable and thereby avoid the current
problem that the requirement doesn't mean anything.

> Tail recursion at least is a clear syntactic property 

Yes. I agree. But the standard library isn't defined
in Ocaml but a more abstract semantics. Clearly one
wishes to allow for Ocaml implementations, C implementations,
and even machine code implementations.

The usual technique is to specify a machine abstraction,
define semantics in terms of that, and then bind the
compiler performance to the abstraction.

> That a tail-recursive
> function uses constant space is then a well-understood QOI issue. No serious
> FP implementation would dare not to meet this criterion.

First, Ocaml isn't a FP. One can certainly introduce
O(n) auxilliary store in a loop (or tail rec function)
using mutable state.

Second, I do agree that one expects a tail recursive calls
to be implemented as loops. This is a serious problem
in Felix because it generates C: procedures are easily
optimised: they never use C-stack except transiently, 
functions are not quite so easy because they do.

Third, tail-rec in Ocaml isn't quite so clear due to
exception handling (still well defined though).

Fourth, it is quite possible for a code to contain
both tail calls and non-tail calls: use linear stack,
instead of quadradic for example. Tail-rec or not
is too black and white.

Fifth: a tail rec function can still be high complexity.
It depends on the actual implementation. You CAN
sort a list using a tail-rec bubble sort... or a tail
rec function allocating n copies of the list for fun .. 
(yeah it still wouldn't blow the stack ..)

So generally, I do agree that the fact the Ocaml docs
now say 'tail-rec' where before there was no annotation at all:
this is a Good Thing (TM).

I don't want the implication removed from the library!
I'd just like to see it stated more normatively.
No hurry either. Just a note to think about, because there
are more and more people using Ocaml, and that does tend
to make any imprecision come out, especially new users
not familiar with the 'common understanding' about things
like 'tail-rec'.

BTW: for some STL algorithms, the EXACT number of calls
the algorithm makes to the copy constructor is mandated.
(The copy algorithm). The question arose if an implementation
was permitted to make a copy like this:

	tmp = *p++
	*q++ = tmp

and the answer is NO, that is banned. Exactly n calls are 
allowed and no more. Each object is copied *exactly* once.
No 'O' notation about it.

-- 
John Skaller, mailto:skaller@users.sf.net
voice: 061-2-9660-0850, 
snail: PO BOX 401 Glebe NSW 2037 Australia
Checkout the Felix programming language http://felix.sf.net



-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [Caml-list] List.rev
  2004-05-01 10:09           ` Nicolas Cannasse
@ 2004-05-02 16:04             ` Brian Hurt
  0 siblings, 0 replies; 27+ messages in thread
From: Brian Hurt @ 2004-05-02 16:04 UTC (permalink / raw)
  To: Nicolas Cannasse; +Cc: Richard Jones, caml-list

On Sat, 1 May 2004, Nicolas Cannasse wrote:

> > Are there automatic ways to transform non-tail-recursive functions
> > into tail-recursive ones?
> >
> > Rich.
> 
> You can have a look at ExtLib sources. We provide tail-recursive
> implementations for each List operations (with same "little o" complexity).
> 

This is actually quite bad advice (sorry, Nicolas)- many of the "tricks" 
we do in Ext-Lib are not for newbies.  I'm thinking specifically of the 
Obj.magic stuff.  If you find yourself doing this anywhere else, you are 
almost certainly screwing up.

There is a fairly standard set of tricks I use to turn non-tail-recursive 
functions into tail-recursive functions.  The two most important ones are:

1) build lists backwards, then reverse them when they're done.  For 
example, List.append could be implemented:
	let append alist blist =
		let revlist = List.rev_append blist (List.rev alist) in
		List.rev revlist
	;;

2) Hoist recursive calls out of try/catch clauses, introducing variables
to detect when an exception was thrown.  For example, to read all the 
lines of a channel into a list of strings, do:
	let readfile chan = 
		let rec loop accum =
			let eof, line = 
				try
					false, (input_line chan)
				with
					| End_of_file ->
						true, ""
			in
			if (eof) then
				List.rev accum
			else
				loop (line :: accum)
		in
		loop []
	;;


-- 
"Usenet is like a herd of performing elephants with diarrhea -- massive,
difficult to redirect, awe-inspiring, entertaining, and a source of
mind-boggling amounts of excrement when you least expect it."
                                - Gene Spafford 
Brian

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 27+ messages in thread

end of thread, other threads:[~2004-05-02 15:59 UTC | newest]

Thread overview: 27+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2004-04-30 17:54 [Caml-list] "List.index" or "List.unique" functions? Rahul Siddharthan
2004-04-30 18:51 ` Martin Jambon
2004-04-30 19:01 ` Benjamin Geer
2004-04-30 19:07   ` Thanks " Rahul Siddharthan
2004-04-30 19:08 ` Karl Zilles
2004-04-30 19:29   ` Matthieu Sozeau
2004-04-30 20:01     ` Karl Zilles
2004-04-30 20:05   ` Remi Vanicat
2004-04-30 20:47     ` JM Nunes
2004-04-30 20:58       ` Karl Zilles
2004-05-01  1:59   ` [Caml-list] List.rev skaller
2004-05-01  4:18     ` Jon Harrop
2004-05-01  4:38     ` brogoff
2004-05-01  5:12       ` skaller
2004-05-01  7:08         ` William Lovas
2004-05-01  8:10           ` skaller
2004-05-01  8:32             ` Jon Harrop
2004-05-01  9:24               ` skaller
2004-05-02 12:07             ` Andreas Rossberg
2004-05-02 13:29               ` skaller
2004-05-01 10:07         ` Richard Jones
2004-05-01 10:09           ` Nicolas Cannasse
2004-05-02 16:04             ` Brian Hurt
2004-05-01 10:32           ` Jon Harrop
2004-05-01 16:41     ` John Goerzen
2004-05-01 19:11       ` skaller
2004-05-01 10:03 ` [Caml-list] "List.index" or "List.unique" functions? Richard Jones

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).