在没有递归的情况下在 OCaml 中生成整数列表
Generating list of integers in OCaml without recursion
如何使用折叠函数之一生成从 0 到值 n-1 的整数列表?我很困惑如何让 fold_right 到 return 一个列表,而不是 return 只是一个累加值。
这是一个辅助函数,我试图定义它来解决一个更大的问题。这是我的尝试:
-我知道基本情况必须是一个只包含零的列表,因为我不想添加任何小于零的东西。
-我知道我需要减少值 n 以便我可以将 n-1 到 0 的数字放入列表中。
let buildList n =
let ibuildList elem list =
list@[n-1]
in List.fold_right ibuildList n [0];;
但我在最后一行中收到一个错误,强调 "n" 表示表达式的类型为 int 但表达式应为 'a list 类型。 n 不是我通过 [n-1] 转换成列表的整数吗?我哪里错了?
非常抱歉,我至少漏掉了推理的一步。
折叠用于遍历集合。由于您想生成一个列表,而您只有 n
,而不是一个集合,因此您不能以任何合理的方式真正使用 fold。事实上,你想要做的更像是展开。也就是说,您想将 n
展开到一个列表中。
写这个函数很容易,但是用fold写就不容易了
这是 OCaml 中展开的实现:
let rec unfold_right f init =
match f init with
| None -> []
| Some (x, next) -> x :: unfold_right f next
以下是使用 unfold_right
生成整数列表的方法:
let range n =
let irange x = if x > n then None else Some (x, x + 1) in
unfold_right irange 1
下面是你 运行 range
:
时的样子
# range 0;;
- : int list = []
# range 8;;
- : int list = [1; 2; 3; 4; 5; 6; 7; 8]
# range 5;;
- : int list = [1; 2; 3; 4; 5]
替代版本,使用标准 Stream 模块:
(* an infinite stream of natural numbers, starting from 0 *)
let nats =
let rec nats_from n = [< 'n; nats_from (n + 1) >] (* extra syntax *)
in nats_from 0
(* the first n natural numbers: [0; n-1] *)
let range n = Stream.npeek n nats
片[< 'n; nats_from (n + 1) >]
表示一个惰性列表,其中n
为头,下一个自然数为尾。 Stream.npeek n stream
将 stream
和 returns 的前 n
个元素作为列表使用。
测试utop:
utop # #load "dynlink.cma";; (* you need these to work with *)
utop # #load "camlp4o.cma";; (* the Stream's syntactic extension *)
utop # range 1;;
- : int list = [0]
utop # range 5;;
- : int list = [0; 1; 2; 3; 4]
utop # range 10;;
- : int list = [0; 1; 2; 3; 4; 5; 6; 7; 8; 9]
如果您想编译它,请使用以下命令(您需要使用 camplp4o 预处理器):
$ ocamlc -pp camlp4o <filename>.ml
或
$ ocamlopt -pp camlp4o <filename>.ml
如何使用折叠函数之一生成从 0 到值 n-1 的整数列表?我很困惑如何让 fold_right 到 return 一个列表,而不是 return 只是一个累加值。
这是一个辅助函数,我试图定义它来解决一个更大的问题。这是我的尝试:
-我知道基本情况必须是一个只包含零的列表,因为我不想添加任何小于零的东西。
-我知道我需要减少值 n 以便我可以将 n-1 到 0 的数字放入列表中。
let buildList n =
let ibuildList elem list =
list@[n-1]
in List.fold_right ibuildList n [0];;
但我在最后一行中收到一个错误,强调 "n" 表示表达式的类型为 int 但表达式应为 'a list 类型。 n 不是我通过 [n-1] 转换成列表的整数吗?我哪里错了?
非常抱歉,我至少漏掉了推理的一步。
折叠用于遍历集合。由于您想生成一个列表,而您只有 n
,而不是一个集合,因此您不能以任何合理的方式真正使用 fold。事实上,你想要做的更像是展开。也就是说,您想将 n
展开到一个列表中。
写这个函数很容易,但是用fold写就不容易了
这是 OCaml 中展开的实现:
let rec unfold_right f init =
match f init with
| None -> []
| Some (x, next) -> x :: unfold_right f next
以下是使用 unfold_right
生成整数列表的方法:
let range n =
let irange x = if x > n then None else Some (x, x + 1) in
unfold_right irange 1
下面是你 运行 range
:
# range 0;;
- : int list = []
# range 8;;
- : int list = [1; 2; 3; 4; 5; 6; 7; 8]
# range 5;;
- : int list = [1; 2; 3; 4; 5]
替代版本,使用标准 Stream 模块:
(* an infinite stream of natural numbers, starting from 0 *)
let nats =
let rec nats_from n = [< 'n; nats_from (n + 1) >] (* extra syntax *)
in nats_from 0
(* the first n natural numbers: [0; n-1] *)
let range n = Stream.npeek n nats
片[< 'n; nats_from (n + 1) >]
表示一个惰性列表,其中n
为头,下一个自然数为尾。 Stream.npeek n stream
将 stream
和 returns 的前 n
个元素作为列表使用。
测试utop:
utop # #load "dynlink.cma";; (* you need these to work with *)
utop # #load "camlp4o.cma";; (* the Stream's syntactic extension *)
utop # range 1;;
- : int list = [0]
utop # range 5;;
- : int list = [0; 1; 2; 3; 4]
utop # range 10;;
- : int list = [0; 1; 2; 3; 4; 5; 6; 7; 8; 9]
如果您想编译它,请使用以下命令(您需要使用 camplp4o 预处理器):
$ ocamlc -pp camlp4o <filename>.ml
或
$ ocamlopt -pp camlp4o <filename>.ml