我正在閱讀這篇文章While or Tail Recursion in F#, what to use when?有幾個人說,做事的'功能方式'是通過使用maps/fold和higher order函數來代替遞歸和循環。在列表中的位置x處返回項目
我有這個函數返回列表中的位置x項目:
let rec getPos l c = if c = 0 then List.head l else getPos (List.tail l) (c - 1)
怎麼能轉化爲更多的功能?
我正在閱讀這篇文章While or Tail Recursion in F#, what to use when?有幾個人說,做事的'功能方式'是通過使用maps/fold和higher order函數來代替遞歸和循環。在列表中的位置x處返回項目
我有這個函數返回列表中的位置x項目:
let rec getPos l c = if c = 0 then List.head l else getPos (List.tail l) (c - 1)
怎麼能轉化爲更多的功能?
這是一個原始列表函數(也稱爲List.nth
)。
可以使用遞歸,特別是在創建基本構建塊時。雖然將與模式匹配,而不是if-else
,這樣是更好:
let rec getPos l c =
match l with
| h::_ when c = 0 -> h
| _::t -> getPos t (c-1)
| [] -> failwith "list too short"
它可以表達這種功能與List.fold
,但結果比遞歸版本不太清楚。
我不確定你的意思是更多的功能。
您是否將此練習作爲學習練習?
如果沒有,你可能只是試試這個:
> let mylist = [1;2;3;4];;
> let n = 2;;
> mylist.[n];;
你的定義已經相當實用,因爲它採用的是尾遞歸函數,而不是命令式循環結構。但是,它也看起來像Scheme程序員可能寫的東西,因爲您使用的是head
和tail
。
我懷疑你真的在問如何用更習慣的ML風格寫它。答案是使用模式匹配:
let rec getPos list n =
match list with
| hd::tl ->
if n = 0 then hd
else getPos tl (n - 1)
| [] -> failWith "Index out of range."
列表結構的遞歸現在顯示在代碼中。如果模式匹配是非詳盡的,那麼您也會收到警告,因此您不得不處理索引太大的錯誤。
你說得對,函數式編程還鼓勵使用像地圖或摺疊(所謂的無點式)等組合器。但太多它只會導致無法讀取的代碼。在這種情況下,我不認爲這是有保證的。
當然,Benjol是正確的,在實踐中,你只會寫mylist.[n]
。
如果您想使用高階函數對於這一點,你可以這樣做:
let nth n = Seq.take (n+1) >> Seq.fold (fun _ x -> Some x) None
let nth n = Seq.take (n+1) >> Seq.reduce (fun _ x -> x)
但這個想法實在是有基本結構,並結合他們建立任何你想要的。獲取序列的第n個元素顯然是您應該使用的基本塊。如果您想要Benjol提到的第n個項目,請執行myList.[n]
。
對於構建基本構造,使用遞歸或可變循環沒有任何錯誤(並且通常,通過以這種方式執行)。
不是作爲一個實際的解決方案,但作爲一個練習,這裏是表達通過foldr
nth
,或在F#方面的方法之一,List.foldBack
:
let myNth n xs =
let step e f = function |0 -> e |n -> f (n-1)
let error _ = failwith "List is too short"
List.foldBack step xs error n
不錯,但我寧願做'| h :: [] - > h'表示第一個匹配條件 – 2011-09-14 13:41:11