2016-02-20 123 views
1

我試圖交換列表中的兩個元素,並不確定爲什麼地雷不工作。OCaml交換列表中的元素

正確的執行應該做到以下幾點:

list_swap_val [5;6;7;3] 75 => [7;6;5;3] 
list_swap_val [5;6;3] 7 5 => [7;6;3] 

這裏有兩種不同的實現我做過嘗試,但似乎都只是返回原始列表

let rec list_swap l u v = 
    match l with 
    |[] -> [] 
    |h::t -> if h = u then u::(list_swap t u v) 
      else if h = v then v::(list_swap t u v) 
      else h::(list_swap t u v) ;; 

我也試着做了以上但是在比賽報表中,而不是使用if,但兩者都不起作用。我哪裏錯了?感謝您的幫助

+0

你有什麼錯誤信息?請更具體一些。另外,看看「a」,「b」,然後看看「u」和「v」;-) – coredump

+0

哦,我很抱歉,我的意思是保持參數相同。當我嘗試執行示例中的代碼時,我只是得到了返回的相同列表,並且沒有任何更改 –

+0

當您看到一個'u'時,返回列表中的第一個元素應該是'v'(反過來說'v '和'u')。在這裏,如果你在所有情況下建立'h::(list_swap t u v)',那就如同。我用OCaml編碼已經有一段時間了,但我認爲你可以避免使用if和pattern匹配來區分所有的情況。 – coredump

回答

4

您忘記了實際交換值:當您看到u時,返回列表的第一個元素應該是v。在這裏,它是 - 如果你在所有情況下建立h::(list_swap t u v)。 順便說一句,你可以因式分解的遞歸調用,它給你最後這個定義:

let rec list_swap l u v = 
    match l with 
    | [] -> [] 
    | h::t -> (if h = u then v 
       else if h = v then u 
        else h)::(list_swap t u v);; 
4

由於coredump-寫下你可以因式分解它,但你可以更進一步,並注意到這是一個地圖。

let swap u v x = if x = u then v else if x = v then u else x 
let list_swap u v = List.map (swap u v) 
1

如上所述,您忘記了交換。您還可以使用List.map:

let swap u v n = match n with 
    |x when x = u -> v 
    |x when x = v -> u 
    |_ -> n;; 
let list_swap l u v = List.map (swap u v) l;; 

這將調用函數「交換U,V,」列表中的「L」的每個元素(感謝局部評估)。

但是,這隱藏了遞歸調用,你應該知道map不是尾遞歸的。如果你想使用地圖和有尾遞歸性:

let list_swap l u v = List.rev (List.rev_map swap (u v) l);; 

「rev_map」是一樣的「地圖」,除了它反轉,同時列表,它是尾遞歸。所以你之後再次顛倒名單。 「rev」也是尾遞歸!