2017-02-08 250 views
0

我正在研究OCaml中的素數分解的實現。我不是一個功能程序員;以下是我的代碼。素數分解在prime_part函數中遞歸地發生。 primes是從0到num的素數列表。這樣做的目的是,我可以輸入prime_part進入OCaml的解釋,並把它吐了出來,當n = 20,K = 1For循環遍歷遞歸調用Ocaml

2 + 3 + 7 
5 + 7 

我適應is_primeall_primes從OCaml的教程。將需要調用all_primes以在調用prime_part之前生成最多爲b的質數列表。

(* 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 = [] =素數質數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

這裏是代碼的一些意見。

  1. 您可以在OCaml中定義嵌套函數。嵌套函數可以訪問所有以前定義的名稱。因此,您可以使用List.iter而不會丟失對本地變量的訪問權限。

  2. 我看不到任何理由,您的功能prime_part_constructive返回一個整數值。在OCaml中,它會更加習慣於返回值爲()的數值,稱爲「單位」。這是由副作用調用的函數(例如打印值)返回的值。

  3. 符號a.(i)用於訪問數組,而不是列表。在OCaml中列表和數組並不相同。如果您用List.iter替換您的for,您不必擔心這一點。

  4. 要連接兩個列表,請使用@運算符。符號lst.concat在OCaml中沒有意義。

更新

這裏是它的外觀有一個嵌套函數。這個組成函數需要一個數字n和一個int列表,然後寫出列表中每個元素的值乘以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]] 

注意,這個函數返回分區列表。這比寫出來更有用(和功能性)(恕我直言)。

+0

我已編輯原始帖子中的OCaml代碼以反映您的建議更改。當我將它放入OCaml解釋器時,它正在轟炸函數h,因爲它無法訪問'lst'。它給了我一個'Unbound value lst'錯誤。任何想法爲什麼這可能是? – technogeek1995

+0

你的函數'h'沒有被定義爲嵌套函數。如果你想要訪問'lst',你需要在* prime_part_constructive裏面定義*。 –

+0

我把它移到了函數中(見上)。然而,口譯員說它找不到'h'。那是因爲我在使用它之前引用了它?如果是這樣,我怎樣才能在不破壞prime_part函數定義的情況下改變它。 – technogeek1995