我想创建一个从1到n
的整数列表。在Python中,我可以使用range(1, n+1)
来实现,在Haskell中可以使用:take n (iterate (1+) 1)
。
在OCaml中,正确的做法是什么?
我想创建一个从1到n
的整数列表。在Python中,我可以使用range(1, n+1)
来实现,在Haskell中可以使用:take n (iterate (1+) 1)
。
在OCaml中,正确的做法是什么?
我不知道任何成语,但这里有一个使用中缀运算符的相当自然的定义:
# 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]
另外,comprehensions 语法扩展(它为上述语法提供了 [i .. j]
)有可能在未来版本的 OCaml 的“社区版”中被包括进去,以便成为惯用语。不过,如果你刚开始接触这门语言,我不建议你开始尝试语法扩展。
通过Batteries Included,你可以编写更多的程序。
let nums = List.of_enum (1--10);;
--
操作符会从第一个值生成一个枚举到第二个值。 --^
操作符类似,但会枚举一个半开区间(1--^10
将会枚举 1 到 9)。
这在基本的OCaml中可以工作:
# List.init 5 (fun x -> x + 1);;
- : int list = [1; 2; 3; 4; 5]
给你:
let rec range i j =
if i > j then []
else i :: range (i+1) j
请注意,这不是尾递归。现代 Python 版本甚至有一个惰性的范围。
range
函数返回生成器而不是列表。这就是所有这里提出的解决方案的主要问题(它们都需要运行时为一些整数分配空间)。 - Gark Garciaxrange
是生成器版本。 - Darius Bacon继上文提到的Alex Coventry之后,但更加简短。
let range n = List.init n succ;;
> val range : int -> int list = <fun>
range 3;;
> - : int list = [1; 2; 3]
succ
(即 successor 的缩写)是 OCaml 的 Int 模块的一部分,等同于 ((+) 1)
。参考:https://ocaml.org/releases/4.10/htmlman/libref/Int.html - JP Lewrange
的懒惰行为,我建议使用Stream
模块。例如:let range (start: int) (step: int) (stop: int): int stream =
Stream.from (fun i -> let j = i * step + start in if j < stop then Some j else None)
int Stream.t
而不是int stream
。 - hbobenicioOCaml有针对范围进行模式匹配的特殊语法:
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
Core
。List.range 0 1000
let range a b =
List.init (b - a) ((+) a)
let rec range ?(start=0) len =
if start >= len
then []
else start :: (range len ~start:(start+1))
range 10
(* equals: [0; 1; 2; 3; 4; 5; 6; 7; 8; 9] *)
range ~start:(-3) 3
(* equals: [-3; -2; -1; 0; 1; 2] *)
自然而然,我认为最好的答案是直接使用Core,但如果您只需要一个函数并且想要避免完整框架,则此方法可能更好。
有趣的是,下面是使用惰性序列实现类似 Python 的 range
函数的代码:
let range ?(from=0) until ?(step=1) =
let cmp = match step with
| i when i < 0 -> (>)
| i when i > 0 -> (<)
| _ -> raise (Invalid_argument "step must not be zero")
in
Seq.unfold (function
i when cmp i until -> Some (i, i + step) | _ -> None
) from
你可以通过以下方式获取从1到n
的整数列表:
# let n = 10;;
val n : int = 10
# List.of_seq @@ range ~from:1 (n + 1);;
- : int list = [1; 2; 3; 4; 5; 6; 7; 8; 9; 10]
# List.of_seq @@ range 5;;
- : int list = [0; 1; 2; 3; 4]
...或倒数:
# List.of_seq @@ range ~from:20 2 ~step:(-3);;
- : int list = [20; 17; 14; 11; 8; 5]
(* you have to use a negative step *)
# List.of_seq @@ range ~from:20 2;;
- : int list = []
# List.of_seq @@ range 10 ~step:0;;
Exception: Invalid_argument "step must not be zero".
# let (--) i j =
? - Clojurevangelist