对于递归调用Ocaml的循环

时间:2017-02-08 23:05:51

标签: recursion ocaml primes prime-factoring

我正在研究OCaml中的主要分解的实现。我不是一名功能性程序员;以下是我的代码。主要分解在prime_part函数中递归地发生。 primes是从0到num的素数列表。这里的目标是我可以将prime_part键入OCaml解释器并在n = 20,k = 1时将其吐出。

2 + 3 + 7
5 + 7

我从OCaml教程中调整了is_primeall_primes。在all_primes被调用之前,需要调用b来生成最多prime_part的素数列表。

(* adapted from http://www.ocaml.org/learn/tutorials/99problems.html *)
let is_prime n =
    let n = abs n in
    let rec is_not_divisor d =
      d * d > n || (n mod d <> 0 && is_not_divisor (d+1)) in
    n <> 1 && is_not_divisor 2;;

let rec all_primes a b =
  if a > b then [] else
    let rest = all_primes (a + 1) b in
    if is_prime a then a :: rest else rest;;

let f elem =
    Printf.printf "%d + " elem

let rec prime_part n k lst primes =
    let h elem =
        if elem > k then
            append_item lst elem;
        prime_part (n-elem) elem lst primes in
    if n == 0 then begin
        List.iter f lst;
        Printf.printf "\n";
        ()
    end
    else
        if n <= k then
        ()
        else 
            List.iter h primes;
            ();;

let main num = 
    prime_part num 1 [] (all_primes 2 num)

我很大程度上对for循环的隐遁性质感到困惑。我看到List.ittr是OCaml方式,但如果我为List.ittr定义另一个函数,我将无法访问我的变量。我需要访问这些变量来递归调用prime_part。有什么更好的方法呢?

我可以在Ruby中阐述我想用OCaml完成的事情。 n =任意数字,k = 1,lst = [],primes =素数0到n的列表

def prime_part_constructive(n, k, lst, primes)
if n == 0
  print(lst.join(' + '))
  puts()
  end
  if n <= k
    return
  end
  primes.each{ |i|
    next if i <= k
    prime_part_constructive(n - i, i, lst+[i], primes)
    }
end

1 个答案:

答案 0 :(得分:1)

以下是对您的代码的一些评论。

  1. 您可以在OCaml中定义嵌套函数。嵌套函数可以访问所有先前定义的名称。因此,您可以使用List.iter而不会失去对本地变量的访问权限。

  2. 我没有看到您的函数prime_part_constructive返回整数值的任何原因。在OCaml中返回值()(称为&#34; unit&#34;)将更加惯用。这是为其副作用(例如打印值)调用的函数返回的值。

  3. 符号a.(i)用于访问数组,而不是列表。 OCaml中的列表和数组不同。如果您将for替换为List.iter,则您不必担心这一点。

  4. 要连接两个列表,请使用@运算符。在OCaml中,符号lst.concat没有意义。

  5. <强>更新

    以下是它具有嵌套功能的方式。这个组成函数需要一个n和一个整数列表,然后写出列表中每个元素的值乘以n

    let write_mults n lst =
        let write1 m = Printf.printf " %d" (m * n) in
        List.iter write1 lst
    

    write1函数是嵌套函数。请注意,它可以访问n

    的值

    更新2

    这是我写这个函数时得到的:

    let prime_part n primes =
        let rec go residue k lst accum =
            if residue < 0 then
                accum
            else if residue = 0 then
                lst :: accum
            else
                let f a p =
                    if p <= k then a
                    else go (residue - p) p (p :: lst) a
                in
                List.fold_left f accum primes
        in  
        go n 1 [] []
    

    它适用于您的示例:

    val prime_part : int -> int list -> int list list = <fun>
    # prime_part 12 [2;3;5;7;11];;
    - : int list list = [[7; 5]; [7; 3; 2]]
    

    请注意,此函数返回分区列表。这比写出来更有用(和功能性)(恕我直言)。