2017-09-14 43 views
0

我是功能編程(RationalML/OCaml)的新手。限制遞歸浮動列表的前三個元素

我有一個浮動列表。我想獲得列表中的前三個非零項目,而不是更多。項目可以是正數,負數和零。

在前三個非零浮點數被提取前,如何限制遞歸?

我的想法做類似的:

switch (list) { 
    | [first, second, third, ...rest] => (first +. second +. third) /. 3.0 
    | _ => 0.0 
}; 

但我怎麼能保證firstsecondthird非零花車?如果是,則遞歸丟棄它們直到找到三個非零浮點數 - 或返回0.0

回答

1

一個更好的方式來做到這一點使用遞歸是使它更通用的:不是找到3第一非零,讓我們找到n第一非零。

下面是一個OCaml實現,我不知道Reason。

let rec find_n l n ~f = 
    if n = 0 then [] 
    else match l with 
    | [] -> failwith "Cannot find enough items" 
    | h::t -> 
     if f h then 
     h :: (find_n t (n-1) ~f) 
     else 
     find_n (t n ~f) 

這裏是函數的簽名:

val find_n : 'a list -> int -> f:('a -> bool) -> 'a list = <fun> 

有很多怎麼回事,但它不是那麼糟糕。這裏的邏輯是這樣的:

如果我想從列表中3項:

  • 如果它的頭相匹配,那麼我需要尋找在尾2項。
  • 否則,我仍然需要在尾部尋找3個物品。

其他的一切只是附加邏輯:

  • 如果我在尋找空的,我就完了。
  • 如果列表爲空,我仍然需要查找更多項目,則失敗。

關於尾遞歸的詞

不幸的是,上面的實現不是tail-recursive,這意味着它將在大型列表失敗。使函數尾遞歸的常用技術是使用一個累加器acc在下面的代碼中)來存儲中間結果。然後,我們將這個額外的邏輯封裝在本地幫助函數(通常稱爲loopaux)中,以便累加器不會出現在函數的簽名中。

let find_n l n ~f = 
    let rec loop l' n' acc = 
    if n' = 0 then acc else 
     match l' with 
     | [] -> failwith "Cannot find enough items" 
     | h::t -> 
      if f h then 
      loop t (n' - 1) (h::acc) 
      else 
      loop t n' acc 
    in 
    loop l n [] 
+1

非常感謝!對於那些希望看到ReasonML語法的用戶,可以使用此工具在OCaml和RationalML片段之間進行轉換。 https://reasonml.github.io/try/?ocaml=DYUwLgBAZglgdgEwPpwsCqB+UIF4IGFHEmlnkWVXU2130ONMUBQBokATiAMZoD2-AA5oA5BnEBDHn1xtCMHHHH4ADBDAALEKml8QwAM4h5RALaSwPTWIgB3GFtOEAPhADaAXQgBaAHzQkjDADloQAEQAwpJwcPyQsIgQOvwArgDmNo4gZobhzgRumgBcxZD+BcSK0BA2WjqVJMCCIpAAFMq+EACMAJQQbSXFer2NhAbGY0TNwhoSEHry8PIzIuioXkA –

0

Got it!

List.filer可用於過濾掉等於零的元素。

let filtered = List.filter (fun item => item != 0.0) list; 
switch (filtered) { 
    | [first, second, third, ...rest] => (first +. second +. third) /. 3.0 
    | _ => 0.0 
}; 
+4

請注意,即使在找到三個非零浮點數後,這將遍歷整個列表。 –