我编写了这些函数来构建一个函数的序列,我在测试时遇到堆栈溢出错误
let rec from_fun f ()=
match f () with
| None -> Nil
| Some e -> Cons(e, from_fun f)
from_fun (fun () -> let x = 0 in if x<10 then Some (x+1) else None)
感谢
答案 0 :(得分:4)
您的函数始终返回Some 1
。它永远不会返回None
。所以序列是无限长的,堆栈在构建时会溢出。
如果您希望函数在调用时返回不同的值,则可以执行两项操作。首先,您可以传递不同的参数。对于from_fun
的设计,这是不可能的 - 函数的参数始终为()
。其次,你的功能可能不纯。即,该函数可以保持一些可变状态。
答案 1 :(得分:2)
以下是生成器的示例:
let range_generator from below step =
let counter = ref from
in fun () ->
if (!counter < below)
then (let result = (Some !counter) in
counter := !counter + step;
result)
else None
例如,对range_generator 0 10 2
的调用会返回内部counter
可变变量的闭包,该变量会生成低于10的所有自然偶数:
# let gen = range_generator 0 10 2;;
val gen : unit -> int option = <fun>
每次调用gen
都可能会改变内部计数器:
# gen();;
- : int option = Some 0
# gen();;
- : int option = Some 2
# gen();;
- : int option = Some 4
# gen();;
- : int option = Some 6
# gen();;
- : int option = Some 8
# gen();;
- : int option = None
# gen();;
- : int option = None
使用您的功能:
# from_fun (range_generator 0 5 1);;
- : int list = [0; 1; 2; 3; 4]
答案 2 :(得分:1)
您使用的变量x
是您正在使用的匿名函数的本地变量。因此,该函数始终返回Some 1
。
您可能想要做的是函数采取参数:
let rec from_fun f n =
match f n with
| None -> Nil
| Some e -> Cons(e, from_fun f e)
let seq = from_fun (fun x -> if x<10 then Some (x+1) else None) 0
编辑: 这是一个具有适当类型签名的解决方案:
let rec from_fun f () =
match f () with
| None -> Nil
| Some e -> Cons(e, from_fun f ())
let x = ref 0
let seq = from_fun
(fun () ->
let v = !x in
if v < 10
then begin
x := v + 1;
Some v
end
else None)
()
值得注意的是,由于副作用,您必须在构建新序列之前重新初始化x
。参数传递给unit
的{{1}}参数是不必要的,您可以删除它。