2009-11-03 63 views
8

我想要一個List.map的尾遞歸版本,所以我寫了我自己的。那就是:可選參數不能被刪除?

let rec list_map f l ?(accum=[])= 
    match l with 
     head :: tail -> list_map f tail ~accum:(head :: accum) 
    | [] -> accum;; 

每當我編譯這個功能,我得到:

File "main.ml", line 69, characters 29-31: 
Warning X: this optional argument cannot be erased. 

tutorial說,這意味着,我試圖創建不帶非可選參數的函數。但上面的函數顯然採用非可選參數。

我可能只是在做一些非常愚蠢的事情,但是什麼?

+1

你應該看看ocaml郵件列表上關於尾遞歸地圖的最新帖子。 http://groups.google.com/group/fa.caml/browse_thread/thread/8b2a70a767e6a433 – nlucaroni 2009-11-03 14:32:14

回答

3

以前的解決方案可以編譯,但不會給出預期的結果。函數f從不應用於參數。正確的代碼是:

let rec list_map f ?(accum = []) l = match l with 
    | head :: tail -> list_map f ~accum:(f head :: accum) tail 
    | [] -> accum;; 

推斷出的類型是:

val list_map : ('a -> 'b) -> ?accum:'b list -> 'a list -> 'b list = <fun> 

...對比的錯誤之一:

val list_map : 'a -> ?accum:'b list -> 'b list -> 'b list = <fun> 

請注意,這個結果清單逆轉:

# list_map ((**) 2.) [1.;2.;3.;4.];; 
- : float list = [16.; 8.; 4.; 2.] 

...和等於函數rev_list from the List module

# List.rev_map ((**) 2.) [1.;2.;3.;4.];; 
- : float list = [16.; 8.; 4.; 2.] 

所以,你可能想改變你的函數爲:

let rec list_map f ?(accum = []) l = match l with 
    | head :: tail -> list_map f ~accum:(f head :: accum) tail 
    | [] -> List.rev accum;; 

...這應該是尾遞歸以及(根據手冊)並以原始順序返回列表:

# list_map ((**) 2.) [1.;2.;3.;4.];; 
- : float list = [2.; 4.; 8.; 16.] 
12

您需要一個非可選參數可選一個。 只要改變你的函數的參數的順序:

let rec list_map f ?(accum=[]) l= 
    match l with 
    head :: tail -> list_map f ~accum:(head :: accum) tail 
    | [] -> accum;; 
+1

非常感謝。那人會絆倒我很多。我習慣於使可選參數最後像Python和C++所要求的一樣。 :-( – 2009-11-03 13:12:04

13

呀你非可選參數不能爲過去的,因爲自OCaml的支持部分應用程序,缺少一個最後的可選參數的函數將只是看起來像一個部分應用函數仍在尋找可選參數。告訴你不打算提供可選參數的唯一方法是它看到你已經提供了一個參數。

如果你有最後擁有它,你可以以後它把虛擬unit說法:

let rec list_map f l ?(accum=[])() = 
    match l with 
     head :: tail -> list_map f tail ~accum:(head :: accum)() 
    | [] -> accum;; 

但在這種情況下,耶改變順序會更好。

+0

所以應用該函數也需要虛擬'()'參數。 – weakish 2017-08-28 06:06:00