Question

I want to create a list of integers from 1 to n. I can do this in Python using range(1, n+1), and in Haskell using: take n (iterate (1+) 1).

What is the right OCaml idiom for this?

Was it helpful?

Solution

There is no idiom that I know of, but here is a fairly natural definition using an infix operator:

# let (--) i j = 
    let rec aux n acc =
      if n < i then acc else aux (n-1) (n :: acc)
    in aux j [] ;;
      val ( -- ) : int -> int -> int list = <fun>
# 1--2;;
- : int list = [1; 2]
# 1--5;;
- : int list = [1; 2; 3; 4; 5]
# 5--10;;
- : int list = [5; 6; 7; 8; 9; 10]

Alternatively, the comprehensions syntax extension (which gives the syntax [i .. j] for the above) is likely to be included in a future release of the "community version" of OCaml, so that may become idiomatic. I don't recommend you start playing with syntax extensions if you are new to the language, though.

OTHER TIPS

With Batteries Included, you can write

let nums = List.of_enum (1--10);;

The -- operator generates an enumeration from the first value to the second. The --^ operator is similar, but enumerates a half-open interval (1--^10 will enumerate from 1 through 9).

Here you go:

let rec range i j = if i > j then [] else i :: (range (i+1) j)

Note that this is not tail-recursive. Modern Python versions even have a lazy range.

This works in base OCaml:

# List.init 5 (fun x -> x + 1);; - : int list = [1; 2; 3; 4; 5]

OCaml has special syntax for pattern matching on ranges:

let () =
  let my_char = 'a' in
  let is_lower_case = match my_char with
  | 'a'..'z' -> true (* Two dots define a range pattern *)
  | _ -> false
  in
  printf "result: %b" is_lower_case

To create a range, you can use Core:

List.range 0 1000

If you use open Batteries (which is a community version of the standard library), you can do range(1,n+1) by List.range 1 `To n (notice the backquote before To).

A more general way (also need batteries) is to use List.init n f which returns a list containing (f 0) (f 1) ... (f (n-1)).

A little late to the game here but here's my implementation:

let rec range ?(start=0) len =
    if start >= len
    then []
    else start :: (range len ~start:(start+1))

You can then use it very much like the python function:

range 10 
     (* equals: [0; 1; 2; 3; 4; 5; 6; 7; 8; 9] *)

range ~start:(-3) 3 
     (* equals: [-3; -2; -1; 0; 1; 2] *)

naturally I think the best answer is to simply use Core, but this might be better if you only need one function and you're trying to avoid the full framework.

BTW, in Haskell you'd rather use

enumFromTo 1 n
[1 .. n]

These are just unnecessary.

take n [1 ..]
take n $ iterate (+1) 1

Following on Alex Coventry from above, but even shorter.

let range n = List.init n succ;;    
> val range : int -> int list = <fun>   
range 3;;                           
> - : int list = [1; 2; 3]              

If you don't need a "step" parameter, one easy way to implement this function would be:

let range start stop = List.init (abs @@ stop - start) (fun i -> i + start)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top