从函数构建序列

时间:2018-05-16 05:01:45

标签: ocaml

我编写了这些函数来构建一个函数的序列,我在测试时遇到堆栈溢出错误

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)

感谢

3 个答案:

答案 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}}参数是不必要的,您可以删除它。