实现一个适用于循环列表的 'List.map' 函数
Implement a 'List.map' function that works on a circular list
所以,我发现 Ocaml 支持使用 let rec
创建循环列表。
utop # let rec ones = 1::ones;;
val ones : int list = [1; <cycle>]
非常简洁,甚至可以在 utop 中打印出来而不会爆炸。
但是当我尝试对这种数据使用 List.map
时,它确实爆炸了:
utop # let twos = List.map ((+) 1) ones;;
Stack overflow during evaluation (looping recursion?).
Raised by primitive operation at Stdlib__List.map in file "list.ml", line 92, characters 32-39
Called from Stdlib__List.map in file "list.ml", line 92, characters 32-39
...
这有点令人失望,但并非完全出乎意料。
现在的问题是,是否可以实现一个 'better' 地图函数来正确处理这个问题。 IE。你会做这样的事情:
let twos = betterMap ((+) 1) ones;;
它不会爆炸,而是能够正确检测循环并产生:
val twos : int list = [2; <cycle>]
由于 ones
的列表虽然在自身上循环,但实际上是一个有限结构,所以感觉这应该是可能的。但是怎么办?
只有当周期在统计上已知时,才能创建循环列表。因此,如果事先不知道列表中循环的拓扑结构,就不可能创建适用于任何循环列表的映射函数。例如,此函数适用于 1-cycle 列表:
let map_1_cycle f = function
| [] -> []
| a :: l ->
let rec answer = f a :: answer in
answer
通用解决方案是使用序列,因为作为惰性列表的一种形式,它们对元素的无限序列有更好的支持:
let ones = Seq.repeat 1
let twos = Seq.map ((+) 1) ones
所以,我发现 Ocaml 支持使用 let rec
创建循环列表。
utop # let rec ones = 1::ones;;
val ones : int list = [1; <cycle>]
非常简洁,甚至可以在 utop 中打印出来而不会爆炸。
但是当我尝试对这种数据使用 List.map
时,它确实爆炸了:
utop # let twos = List.map ((+) 1) ones;;
Stack overflow during evaluation (looping recursion?).
Raised by primitive operation at Stdlib__List.map in file "list.ml", line 92, characters 32-39
Called from Stdlib__List.map in file "list.ml", line 92, characters 32-39
...
这有点令人失望,但并非完全出乎意料。
现在的问题是,是否可以实现一个 'better' 地图函数来正确处理这个问题。 IE。你会做这样的事情:
let twos = betterMap ((+) 1) ones;;
它不会爆炸,而是能够正确检测循环并产生:
val twos : int list = [2; <cycle>]
由于 ones
的列表虽然在自身上循环,但实际上是一个有限结构,所以感觉这应该是可能的。但是怎么办?
只有当周期在统计上已知时,才能创建循环列表。因此,如果事先不知道列表中循环的拓扑结构,就不可能创建适用于任何循环列表的映射函数。例如,此函数适用于 1-cycle 列表:
let map_1_cycle f = function
| [] -> []
| a :: l ->
let rec answer = f a :: answer in
answer
通用解决方案是使用序列,因为作为惰性列表的一种形式,它们对元素的无限序列有更好的支持:
let ones = Seq.repeat 1
let twos = Seq.map ((+) 1) ones