5位数字的数量,没有重复的数字大于12345

时间:2019-04-28 01:15:08

标签: ocaml

我是OCaml和算法的初学者。 我正在尝试获取5位数字的数量,且没有重复的数字大于12345。

这是我在OCaml中所做的事情,我尝试尽可能使尾递归,并且还使用了流。但仍然由于大小而导致堆栈溢出:

type 'a stream = Eos | StrCons of 'a * (unit -> 'a stream)

let rec numberfrom n= StrCons (n, fun ()-> numberfrom (n+1))

let nats = numberfrom 1

let rec listify st n f=
  match st with
  |Eos ->f []
  |StrCons (m, a) ->if n=1 then f [m] else listify (a ()) (n-1) (fun y -> f (m::y))


let rec filter (test: 'a-> bool) (s: 'a stream) : 'a stream=
  match s with
  |Eos -> Eos
  |StrCons(q,w) -> if test q then StrCons(q, fun ()->filter test (w ()))
      else filter test (w ())



let rec check_dup l=
  match l with
  | [] -> false
  | h::t->
      let x = (List.filter (fun x -> x = h) t) in
      if (x == []) then
        check_dup t
      else
        true;;

let digits2 d =
  let rec dig acc d =
    if d < 10 then d::acc
    else dig ((d mod 10)::acc) (d/10) in
  dig [] d

let size a=
  let rec helper n aa=
    match aa with
    |Eos-> n
    |StrCons (q,w) -> helper (n+1) (w())
  in helper 0 a

let result1 = filter (fun x -> x<99999 && x>=12345 && (not (check_dup (digits2 x)))) nats



(* unterminating : size result1 *)
        (*StackOverflow: listify result1 10000 (fun x->x) *)

2 个答案:

答案 0 :(得分:1)

我无法重现您报告的问题。当我加载您的代码时,我看到以下内容:

# List.length (listify result1 10000 (fun x -> x));;
- : int = 10000
# List.length (listify result1 26831 (fun x -> x));;
- : int = 26831

您的系统可能比我的系统更受资源限制。

让我说,编写尾部递归函数的通常方法是将列表反向构建,然后在最后将其反向。可能看起来像这样:

let listify2 st n =
    let rec ilist accum st k =
        match st with
        | Eos -> List.rev accum
        | StrCons (m, a) ->
            if k = 1 then List.rev (m :: accum)
            else ilist (m :: accum) (a ()) (k - 1)
    in
    if n = 0 then []
    else ilist [] st n

如果您请求的元素多于流中的元素,那么listify不会终止的问题仍然存在。最好引入一种方法来检测流的结尾并在该点返回Eos。例如,filter函数可能接受一个返回三个可能值的函数(应滤除元素,不滤除元素,流应结束)。

答案 1 :(得分:1)

问题是流result1的大小不确定。

实际上,nats是一个永无止境的流:它永远不会返回Eos

但是,过滤无休止的流会导致另一个无休止的流 因为经过过滤的流仅在基础流这样做之后才返回Eos

let rec filter (test: 'a-> bool) (s: 'a stream) : 'a stream=
  match s with
  | Eos -> Eos
  | StrCons(q,w) -> if test q then StrCons(q, fun ()->filter test (w ()))
      else filter test (w ())

因此,size result1被卡住,试图到达整数的末尾。

还要注意,在最新版本的标准库中,您的类型stream被称为Seq.node