2012-02-21 29 views
3

這些簡單的功能尾遞歸我有這兩個功能如何在F#

//Remove all even indexed elements from a list and return the rest 
let rec removeEven l = 
match l with 
| x0::x1::xs -> x1::removeEven (xs) 
| [] -> [] 
| [_] -> [] 

//combine list members into pairs 
let rec combinePair l = 
match l with 
| x0::x1::xs -> (x0,x1) :: combinePair(xs) 
| [] -> [] 
| [_] -> [] 

這項工作。

但是我現在認爲我是在這樣做的,我不妨學習一些關於尾遞歸的知識,我很難掌握它。

這就是爲什麼我認爲如果我可以幫助某些功能做出自己的尾遞歸,或許它會變得更清楚它是如何工作的,而不是閱讀一個我可能不瞭解的例子,代碼(記住,我是一個完整的f#新手:))

任何其他有關我的代碼的建設性意見當然是最受歡迎的!

+0

我認爲這是正確的。 這是應該刪除偶數索引,而不是偶數值的元素,在這種情況下1有索引0和2有索引1 – PNS 2012-02-21 18:16:45

+0

爲什麼'removeEven [1; 2]'return'[2]'?我在我的答案中複製了它的行爲,但它似乎應該被稱爲'returnEven'或'removeOdd'什麼的。 – Daniel 2012-02-21 18:18:52

+0

抱歉刪除我的評論。我改寫了它。所以_even_是指索引?好的。 – Daniel 2012-02-21 18:19:46

回答

3

制定職能尾遞歸在F#(在這種情況下acc)用列表來累積結果,扭轉它得到正確的次序的一種典型方式:

let removeEven l = 
    let rec loop xs acc = 
     match xs with   
     | [] | [_] -> acc 
     | _::x1::xs' -> loop xs' (x1::acc) 
    loop l [] |> List.rev 

let combinePair l = 
    let rec loop xs acc = 
     match xs with   
     | [] | [_] -> acc 
     | x0::x1::xs' -> loop xs' ((x0, x1)::acc) 
    loop l [] |> List.rev 

由於我們簡單地返回後的結果每次遞歸調用loop,這些函數都是尾遞歸的。

你的函數看起來相當不錯,但還是有一些意見:

  • 縮進在F#重要。我更喜歡match... withlec rec聲明後面的幾個空格。
  • 模板匹配案例應遵循一致的順序。首先從基本案例開始,這是一個好主意。
  • 只要有fun t -> match t with的模式,function關鍵字就很自然地用於縮短功能。
  • 最好擺脫不必要的括號,特別是在有一個參數的函數中。

應用上述意見,你的功能變得如下:

// Remove all even indexed elements from a list and return the rest 
let rec removeEven = function 
    | [] | [_] -> [] 
    | _::x1::xs -> x1::removeEven xs 

// Combine list members into pairs 
let rec combinePair = function 
    | [] | [_] -> [] 
    | x0::x1::xs -> (x0, x1)::combinePair xs 
+0

真的很好! thx很多,這是我想要的。 不完全確定我明白什麼是「循環l [] |> List.rev」 行。我的意思是我知道它應該扭轉列表,但爲什麼循環l []?以及何時能夠達到該rec代碼? – PNS 2012-02-21 18:02:55

+1

'| [] - > [] | [_] - > []'也可以摺疊成'| [] | [_] - > []',保存兩行。 – ildjarn 2012-02-21 18:04:05

+0

@ildjarn:你的建議已經被應用:)。 – pad 2012-02-21 18:05:50

2

如果你需要一個較慢,維護的方式做到這一點,使用更多的內存,你可以使用一個延續。

let removeEven items = 
    let rec loop f = function 
    | _::h::t -> loop (fun acc -> f (h::acc)) t 
    | [] | [_] -> f [] 
    loop id items 

但是,嘿,它是尾遞歸的。

+0

+1的諷刺評論。 :-P – ildjarn 2012-02-21 18:11:15