2017-10-19 94 views
2

請考慮,鑑於x一個C程序,將返回yz這樣y + z * 2 = x,爲儘可能小的y。粗略地說,我可以創建一個嵌套的循環:嵌套循環和函數式編程

for(y = 0; y < x; ++ y){ 
    for(z = 0; z < x; ++z){ 
     if(y + 2 * z == x){ 
      printf("%d + 2 * %d = %d", y, z, x); 
     } 
    } 
} 

我怎麼能在功能的方式翻譯這種嵌套循環?這可行嗎?是合理還是我只是錯誤的判斷方法?到目前爲止,我最好的嘗試:

let foo x = 
    let rec aux (y, z, q) = 
     match (y + z * 2) with 
     r when r = q -> (y, z) 
     |_  -> aux(y + 1, z + 1, q) //How to check different values of z 
    aux(0, 0, x)       //for each value of y? 

這是行不通的,因爲它只會增加雙方yz。如何檢查z的不同值,對於y的每個值?

+0

程序語言(如C)和功能語言(如F#)在編程時代表了兩種不同的範例。因此,你不能真正做他們之間的直接翻譯(你*可以*,但它不會很好的翻譯,很可能相反),你經常不得不*。 –

+2

至於你的功能片段的評論中的問題 - >使用第二個遞歸函數。假設這是關於無符號整數的,爲什麼不直接計算結果? –

+0

'y = x%2; z = x/2'會做....(並且可以用功能代碼表示) –

回答

4

您必須在比賽中添加這些檢查。

在這裏看到你的代碼是缺少:

let foo x = 
    let rec aux (y, z, q) = 
     match (y + z * 2) with 
     | r when r = q -> (y, z) 
     | _ when y = q -> failwith "not found !" 
     | _ when z = q -> aux (y + 1, 0, q) 
     | _   -> aux (y, z + 1, q) 
    aux (0, 0, x) 

,這裏是一個不同的方法,同樣的功能,但不遞歸:

let foo2 x = 
    let s = 
     {0 .. x} |> Seq.collect (fun y -> 
      {0 .. x} |> Seq.collect (fun z -> 
       seq [y, z])) 
    Seq.find (fun (y, z) -> y + z * 2 = x) s 

這在F#可以使用序列表達式來寫:

let foo3 x = 
    let s = seq { 
     for y in {0 .. x} do 
      for z in {0 .. x} do 
       yield (y, z)} 
    Seq.find (fun (y, z) -> y + z * 2 = x) s 

它類似於你原來的C程序。

+0

您不需要括號。 「對於0 .. x做y」同樣適用。 – Lars

+0

感謝Gustavo,你的例子正在幫助我澄清幾個概念。我正在練習他們!我只有一個問題。在你的第一個片段中,什麼是r?我不是陛下,我說得對。它有價值嗎?這只是一個名字嗎? – Worice

+0

@Worice其實''r''來自你的代碼,而不是我的。但是,它包含評估''(y + z * 2)''的結果。如果你問我,我會重新編寫這個匹配,或者使用if和elif表達式,但我只是想盡可能地將代碼粘貼到你的代碼中,並告訴你你錯過了什麼。 – Gustavo