What is the OCaml idiom equivalent to Python's range function?

天涯浪子 提交于 2019-12-03 14:42:55

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!