2010-08-24 43 views
16

Đây là một câu hỏi khá đơn giản, và tôi chỉ muốn kiểm tra xem những gì tôi đang làm và cách tôi diễn giải F # có ý nghĩa như thế nào. Nếu tôi có tuyên bốF # Chức năng so với giá trị

let printRandom = 
    x = MyApplication.getRandom() 
    printfn "%d" x 
    x 

Thay vì tạo printRandom như một chức năng, F # chạy nó một lần và sau đó gán cho nó một giá trị. Vì vậy, bây giờ, khi tôi gọi printRandom, thay vì nhận được một giá trị ngẫu nhiên mới và in nó, tôi chỉ đơn giản nhận được bất cứ điều gì đã được trả lại lần đầu tiên. Tôi có thể giải quyết vấn đề này để xác định nó như sau:

let printRandom() = 
    x = MyApplication.getRandom() 
    printfn "%d" x 
    x 

Đây có phải là cách thích hợp để phân biệt sự khác biệt này giữa các hàm và giá trị tham số không? Điều này có vẻ ít hơn lý tưởng với tôi. Liệu nó có hậu quả trong currying, thành phần, vv?

+2

Lưu ý rằng bạn gần như chắc chắn muốn thêm 'let' trước lần xuất hiện đầu tiên của' x' - nếu không bạn đang thực hiện so sánh và sau đó vứt bỏ kết quả. – kvb

+0

Câu hỏi hay, có vấn đề * chính xác * giống nhau. Thật không may tôi thấy điều này sau khi tôi phát hiện ra giải pháp. – ses011

Trả lời

18

Cách đúng đắn để xem xét điều này là F # không có chức năng như hàm tham số ít. Tất cả các chức năng phải có một tham số, nhưng đôi khi bạn không quan tâm nó là gì, vì vậy bạn sử dụng () (giá trị đơn vị kiểu đơn). Bạn cũng có thể làm cho một chức năng như thế này:

let printRandom unused = 
    x = MyApplication.getRandom() 
    printfn "%d" x 
    x 

hay này:

let printRandom _ = 
    x = MyApplication.getRandom() 
    printfn "%d" x 
    x 

Nhưng () là cách mặc định để thể hiện rằng bạn không sử dụng các tham số. Nó thể hiện sự thật đó với người gọi, vì loại này là unit -> int không phải là 'a -> int; cũng như người đọc, bởi vì trang web cuộc gọi là printRandom() không phải printRandom "unused".

Currying và composition làm trên thực tế dựa vào thực tế là tất cả các hàm lấy một tham số và trả về một giá trị.

Cách phổ biến nhất để viết cuộc gọi với đơn vị, bằng cách này, là với một không gian, đặc biệt là trong các đối tượng không .NET của F # như Caml, SML và Haskell. Đó là bởi vì () là một giá trị singleton, không phải là một cú pháp giống như trong C#.

8

Phân tích của bạn là chính xác.

Ví dụ đầu tiên xác định giá trị chứ không phải hàm. Tôi thừa nhận điều này bắt gặp tôi một vài lần khi tôi bắt đầu với F # là tốt. Đến từ C# nó có vẻ rất tự nhiên mà một biểu thức gán có chứa nhiều câu lệnh phải là một lambda và do đó trì hoãn được đánh giá.

Đây không phải là trường hợp trong F #. Các câu lệnh có thể gần như tùy ý lồng nhau (và nó đá để có các hàm và giá trị được dàn tạp tại địa phương). Một khi bạn cảm thấy thoải mái với điều này, bạn bắt đầu thấy nó như là một lợi thế khi bạn có thể tạo ra các chức năng và sự tiếp tục mà không thể tiếp cận với phần còn lại của hàm.

Cách tiếp cận thứ hai là cách tiêu chuẩn để tạo một hàm mà không có đối số logic. Tôi không biết thuật ngữ chính xác mà nhóm F # sẽ sử dụng cho tuyên bố này mặc dù (có lẽ một hàm lấy một đối số duy nhất của loại unit). Vì vậy, tôi không thể thực sự bình luận về cách nó sẽ ảnh hưởng đến cà ri.

+4

Currying không thực sự áp dụng ở đây vì hàm chỉ có một tham số, thuộc kiểu 'unit'. Ứng dụng một phần không có ý nghĩa: bạn hoàn toàn áp dụng hàm (chuyển '()'), hoặc bạn không gọi nó là gì cả. –

7

Đây có phải là cách thích hợp để rút ra sự khác biệt này giữa các tham số và các giá trị không? Điều này có vẻ ít hơn hơn lý tưởng với tôi. Liệu nó có các hậu quả của trong cà ri, thành phần, không?

Có, những gì bạn mô tả là chính xác.

Đối với giá trị của nó, nó có một hệ quả rất thú vị có thể đánh giá một phần chức năng khai báo. Hãy so sánh hai chức năng:

// val contains : string -> bool 
let contains = 
    let people = set ["Juliet"; "Joe"; "Bob"; "Jack"] 
    fun person -> people.Contains(person) 

// val contains2 : string -> bool 
let contains2 person = 
    let people = set ["Juliet"; "Joe"; "Bob"; "Jack"] 
    people.Contains(person) 

Cả hai chức năng tạo ra kết quả giống nhau, contains tạo ra con người đặt trên khai và tái sử dụng nó, trong khi contains2 tạo người của nó đặt mọi lúc bạn gọi hàm. Kết quả cuối cùng: contains hơi nhanh hơn. Vì vậy, biết sự khác biệt ở đây có thể giúp bạn viết mã nhanh hơn.

3

Cơ quan chuyển nhượng trông giống như các cơ quan chức năng đã chọn một vài lập trình viên không biết. Bạn có thể làm mọi việc trở nên thú vị hơn bằng cách chuyển bài tập trở lại một hàm:

let foo = 
    printfn "This runs at startup" 
    (fun() -> printfn "This runs every time you call foo()") 

Tôi vừa viết một bài đăng blog về nó tại http://blog.wezeku.com/2010/08/23/values-functions-and-a-bit-of-both/.

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