2009-11-03 15 views
8

Tôi muốn có một phiên bản đệ quy đuôi của List.map, vì vậy tôi đã viết của riêng tôi. Ở đây là:Đối số tùy chọn không thể xóa được?

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

Bất cứ khi nào tôi lập chức năng này, tôi nhận được:

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

Các tutorial nói rằng điều này có nghĩa rằng tôi đang cố gắng để tạo một hàm không có tham số không bắt buộc. Nhưng hàm ở trên rõ ràng nhận các đối số không bắt buộc.

Tôi có thể chỉ làm điều gì đó thực sự câm, nhưng sao?

+1

bạn nên xem các bài viết gần đây trên danh sách gửi thư ocaml về các bản đồ đệ quy đuôi. http://groups.google.com/group/fa.caml/browse_thread/thread/8b2a70a767e6a433 – nlucaroni

Trả lời

3

Các giải pháp trước đây sẽ biên dịch, nhưng sẽ không cho kết quả mong đợi. Hàm f không bao giờ được áp dụng cho các đối số. Một mã đúng là:

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

Loại suy ra là:

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

... trái ngược với sai một:

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

Xin lưu ý, rằng kết quả danh sách bị đảo ngược:

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

... và tương đương với chức năng rev_list from the List module:

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

Vì vậy, bạn có thể muốn thay đổi chức năng của bạn vào:

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

... mà nên có đuôi-đệ quy cũng (theo hướng dẫn) và trả về danh sách theo thứ tự ban đầu:

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

Bạn cần một đối số không bắt buộc sau tùy chọn một. Chỉ cần thay đổi thứ tự của các đối số của hàm của bạn:

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

Cảm ơn bạn rất nhiều.Điều đó sẽ giúp tôi rất nhiều. Tôi được sử dụng để làm cho các đối số tùy chọn được cuối cùng như Python và C + + yêu cầu. :-( –

13

Ừ luận không bắt buộc bạn không thể cuối cùng, bởi vì kể từ khi OCaml hỗ trợ các ứng dụng một phần, một hàm thiếu đối số tùy chọn cuối cùng sẽ chỉ trông giống như một hàm được áp dụng một phần mà vẫn đang tìm đối số tùy chọn. Cách duy nhất để nó nói rằng bạn không có ý định cung cấp đối số tùy chọn là nó thấy rằng bạn đã cung cấp một đối số sau nó.

Nếu bạn có để có nó cuối cùng, bạn có thể đặt một giả unit luận sau nó:

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

Nhưng trong trường hợp này vâng thay đổi thứ tự sẽ tốt hơn.

+0

Vì vậy, việc áp dụng hàm cũng cần đối số giả lập '()'. – weakish