I imagine this has been asked before , but anyway ... .
I'm puzzled by the lack of a "range operator" in OCaml (i.e.
something like
[ 1 .. 10 ] to denote the range from one to ten. The reason I
mention this is that I saw one of the OCaml entries on this page -
http://www.uni-karlsruhe.de/~uu9r/lang/html/ocaml.en.html
The entry which outputs the squares from one to ten is -
List.map(function n -> n * n) [1;2;3;4;5;6;7;8;9;10];;
Ok - this can be done with a do-loop , but I'm still amazed that
something like [1..10] hasn't been included in the language. Is there
a (good!) reason for this?
( p.s. - I'm meaning to ask this in a "positive" frame of mind, as I
*like* OCaml. It's just that I find this quite puzzling ! .... :-)
Many thanks in advance for your comments!
Well, it would be a bit odd to have a special syntax for making
lists of consecutive integers. In SML, there are "tabulate"
functions, which work like this:
Standard ML of New Jersey, Version 110.0.7, September 28, 2000
- List.tabulate;
val it = fn : int * (int -> 'a) -> 'a list
- List.tabulate(7,fn x => x);
val it = [0,1,2,3,4,5,6] : int list
- List.tabulate(4,~);
val it = [0,~1,~2,~3] : int list
- List.tabulate(5,fn x => "datapoint" ^ (Int.toString x));
val it =
["datapoint0","datapoint1","datapoint2","datapoint3","datapoint4"]
: string list
And these exist for many datastructures, working the same way:
- Array.tabulate(4,~);
val it = [|0,~1,~2,~3|] : int array
It looks like in OCaml you can do:
Array.init 30 (fun x -> x*x)
but I don't know if there is an equivalent for lists.
--
Jeffrey M. Vinocur * jm...@cornell.edu
http://www.people.cornell.edu/pages/jmv16/
"Well, it would be a bit odd to have a special syntax for making
lists of consecutive integers."
---------------
Why would this be an odd thing? I find that immensely useful in my other
languages!
- David McClain, Sr. Scientist, Raytheon Missile Systems Co., Tucson, AZ
I imagine Jeff considers it a bit odd since the special syntax seems to
buy you so little. I imagine you'd like something like ".." to be like
range pattern matching, but is this really immensely better than, say,
"interval n m"? I'm a big fan of infix syntax but I've confused myself
frequently when overdoing it.
I'd rather that interval were in the standard library (*) and then you
could make an infix syntax of your own.
-- Brian
(*) http://caml.inria.fr/archives/199910/msg00084.html
signature FORLOOPS =
sig
type elem
type sequence
range :: elem -> elem -> sequence
(* range a b is a, a+1, ..., b, or nothing if b<a *)
range_step :: elem -> elem -> elem -> sequence
(* range a b step is like range only with step rather than 1 *)
range_step_unbounded :: elem -> elem -> sequence
(* range a step is like range a b step, but never stops *)
fold_sequence :: ((elem* 'a) -> 'a) -> 'a -> sequence -> 'a
iterate_sequence :: (elem -> ()) -> sequence -> ()
map_sequence :: (elem -> 'a) -> sequence -> [a]
end
and then include a structure
structure ForLoops : FORLOOPS where type int = elem
for various flavours of integers.
Okay, sure, you have a good point that the specific code you point out
looks like tedious work to type ... but I think it is written that way
because it is an example in documentation.
My opinion on the matter is that in FP, you do not need to create a
*sequence* as often as in imperative languages. This is because in
FP languages, you usually have powerful ways to create sequences
functionally. In imperative languages a range function is handy so
you can generate values to iterate over. In Python, you can't live
without range, for instance. In functional programming ... I think
you don't need it much at all.
But, if you really, really want a list sequence ...
Instead of the proposed "interval" function, I prefer this:
let lseq n f =
let rec loop l m =
if m < 0 then l else loop ((f m) :: l) (pred m) in
loop [] (pred n)
Which is analogous to the Array.init function in Ocaml (orthogonality
is good), but it produces a list. Now you can define an integer range:
(* generate list of integers from n through m *)
let range n m = lseq (m - n + 1) (fun x -> x + n)
And you can type your example in the toplevel in a nicer way ...
# List.map(fun n -> n * n) (range 1 10);;
- : int list = [1; 4; 9; 16; 25; 36; 49; 64; 81; 100]
Of course, if you don't mind using arrays in the first place, then the
example would be:
# Array.map(function n -> n * n) (Array.init 10 (fun x -> succ x));;
- : int array = [|1; 4; 9; 16; 25; 36; 49; 64; 81; 100|]
But to return to my original position ... if you show me where you
wish to use a sequence in Ocaml, I think it is probably possible to
refactor your code to be more functional.
cheers,
doug
I meant to add a disclaimer about scientific computation; I
assume you refer to e.g. Matlab, and yes, in such contexts it is
appropriate. But in ML...it doesn't fit with the paradigm.
>I imagine Jeff considers it a bit odd since the special syntax seems to
>buy you so little. I imagine you'd like something like ".." to be like
>range pattern matching, but is this really immensely better than, say,
>"interval n m"? I'm a big fan of infix syntax but I've confused myself
>frequently when overdoing it.
>
>I'd rather that interval were in the standard library (*) and then you
>could make an infix syntax of your own.
Ah, this is something I hadn't even thought of. Sure, defining
the appropriate function is not difficult, and making it infix if
desired isn't either. The issue comes down to what the grammar
permits (and what the parser can handle) as an identifier; I know
SML at least disallows what you're looking for, but lots of other
identifiers would work (say "1 --> 10", that seems reasonable).
Just a brief post to say "many thanks!" for all of your posts in
response to my query . They've all been very helpful to me (as a real
newcomer to OCaml ! ) .
Bye for now !
- Andy