2010-07-07 35 views
7

Dưới đây là mã mà hoạt động tốt:Có thể nào trong F # để xử lý một đối số hàm trung bình?

let f x y z = x + y + z 

let g x y = f x y 
let h x z = z |> f x 

Vì vậy, tôi có thể viết khái niệm "h 1", và hiển thị FSI:

val it : (int -> int -> int) = <fun:[email protected]> 

Nếu tôi gọi là "h 1 2 3", các đối số được áp dụng yêu cầu hợp lý.
Nhưng nếu đối số cuối cùng có một kiểu khác nhau, mọi thứ trở nên khác nhau:

let ff x y (z : string) = x + y 

let gg x y = ff x y 
let hh x (z : string) = z |> ff x 

Bây giờ chức năng hh cuối cùng gây ra một thông báo lỗi:

Script.fsx (119,10): FS0001 lỗi : Loại không phù hợp. Mong đợi một số string -> 'a nhưng được cung cấp int -> string -> int. Loại string không phù hợp với loại int

Tôi hiểu tại sao điều này xảy ra - "z" được gắn vào "ff x" làm cho nó một số thứ hai. Nhưng sau đó tôi mong đợi trong biểu thức ví dụ đầu tiên "h 1 2 3" không hoạt động đúng (được thực hiện như "f 1 3 2"). Nhưng nó hoạt động tốt.

+1

Bạn có chắc chắn 'h 1 2 3' thực thi là' f 1 2 3' chứ không phải 'f 1 3 2'? Sau khi tất cả, 1 + 2 + 3 == 1 + 3 + 2 == 6. Có thể thử với một toán tử không chuyển tiếp? – tzaman

+0

FWIW, các đối số được gắn nhãn của OCaml cho phép bạn áp dụng một phần không đúng thứ tự. –

Trả lời

8

Các chức năng ffgg trong ví dụ của bạn giống nhau - toán tử pipelining cung cấp giá trị cho đối số đầu tiên của hàm ở bên phải. Trong ví dụ của bạn, chức năng ở phía bên tay phải là ff x và bằng cách sử dụng các nhà điều hành pipelining, bạn chỉ định giá trị cho tham số y:

let ff x y (z : string) = 
    printfn "%s" z 
    x + y 

// These two functions are the same: 
let gg x y = ff x y 
let hh x y = y |> ff x 

Không có cú pháp stnadard để xác định khác so với các thông số đầu tiên khi sử dụng chức năng phần ứng dụng. Tuy nhiên, bạn có thể viết hàm bậc cao hơn hoặc toán tử tùy chỉnh để thực hiện điều đó. Ví dụ:

// Takes a function 'f' of type 'b -> 'a -> 'c 
// and a value 'v' of type 'a and creates a function 
// that takes the first argument ('b -> 'c) 
let (|*>) v f = (fun mid -> f mid v);; 

let gg x y = ff x y  // Specifies arguments x and y 
let hh x z = z |*> ff x // Specifies arguments x and z 

Tôi đã đặt tên toán tử |*> để biểu thị rằng bỏ qua một đối số. Bạn có thể xác định toán tử xác định giá trị của các đối số khác tương tự (ví dụ: |**> để bỏ qua hai đối số đầu tiên).

+0

Tomas, cảm ơn bạn đã trả lời. Sử dụng nhà điều hành tùy chỉnh có vẻ là một cách để đi! –

+1

Tôi nghĩ rằng bạn có các đối số lạc hậu trong toán tử đó. Tôi nghĩ rằng nó nên được (vui vẻ cuối cùng -> f v cuối cùng). Ngoài ra, ứng dụng chức năng được ưu tiên hơn các toán tử, vì vậy dòng cuối cùng phải là: (z | *> ff) x Thử kiểm tra điều này bằng phép trừ hoặc chia, chứ không phải là phép cộng. – YotaXP

+0

@YotaXP: Cả hai thứ bạn đã đề cập đều có chủ ý. Nếu bạn viết toán tử theo cách bạn mô tả (ví dụ 'fun last -> fv last'), bạn sẽ không cần hàm lambda chút nào, vì nó sẽ tương đương với' fv' - toán tử '|>' chuẩn . Về điểm thứ hai - ý định là bạn viết 'z | *> ff x', bạn chỉ định' z' làm đối số thứ hai của hàm 'ff x' (và đối số đầu tiên vẫn được chỉ định). Nói cách khác, 'z | *> ff x' tương đương với' fun a -> ff x a z'. –

Các vấn đề liên quan