From: Brian H. <bri...@ql...> - 2003-05-29 18:44:30
|
Sorry, I just had an epiphany on this issue. With enums we always have a good count, right? I mean, we're not implementing my "-1 means we don't know how many elements are in the enumeration". The enum code should use this and never cause an exception to be thrown. Therefor it doesn't need to catch the exceptions either. let iter f e = let c = e.count() in for i = 1 to c do f (e.next()) done let fold f x e = let rec loop c accu = if c <= 0 then accu else loop (c-1) (f (e.next ()) accu) in loop (e.count ()) x Calling next when count == 0, when there are no more elements, is an *error*. Of course it throws an exception. But the Enum code shouldn't do that. And if next doesn't have any more elements and count > 0, then something exceptional did happen. The above code strikes me as being clean and nice. And it solves your problem of an exception from next being "accidentally" caught at a higher level, and enum doesn't catch exceptions. And Enum.next has the same interface as the next passed into Enum.make has. The above code strikes me as being clean and easy to understand. Two comments on this: 1) on some data structures, calling count will be expensive- for example, on lists it's O(N). 2) Your example changes behavior: > > exemple : > > let e1 = List.enum [1;2;3] > let e2 = List.enum [] > > let combine x = > (x , Enum.next e2) > > let l = Enum.of_list (Enum.map combine e1) > > => [] Here, instead of returning the empty list, the above code throws an uncaught exception. Which is actually, I think, the correct thing to do. What you wanted to express above is, I think: let combine a b = a, b in let l = List.of_enum (Enum.map2 combine e1 e2) But this also allows you to do: let combine x = try (x, Enum.next e2) with No_more_elements -> x, 0 in let l = List.of_enum (Enum.map combine e1) As a general note, data structures we add in the future should have fast (O(1)) length routines, even at the cost of a little more bookkeeping. Not a lot we can do with lists at this point, but if everything else should be fast. And at worst case we spin through the data structure twice. This actually encourages piling multiple maps onto a single list, and not actually instantiating the intermediate lists. Sort of the cheap version of lazy evaluation. Brian |