问题
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?
回答1:
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.
回答2:
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).
回答3:
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.
回答4:
This works in base OCaml:
# List.init 5 (fun x -> x + 1);;
- : int list = [1; 2; 3; 4; 5]
回答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
回答6:
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)).
回答7:
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.
回答8:
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]
回答9:
BTW, in Haskell you'd rather use
enumFromTo 1 n
[1 .. n]
These are just unnecessary.
take n [1 ..]
take n $ iterate (+1) 1
回答10:
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)
回答11:
Came up with this:
let range a b =
List.init (b - a) ((+) a)
来源:https://stackoverflow.com/questions/243864/what-is-the-ocaml-idiom-equivalent-to-pythons-range-function