6

OK, đã lâu rồi và não của tôi có thể không hoạt động ở cấp độ Haskell, nhưng tôi không thể hiểu một ví dụ từ 'Learn You a Haskell'.Ứng dụng chức năng trong Haskell

Phần được gọi chức năng ứng dụng với $, và có ví dụ về cách $ thể được định nghĩa:

($) :: (a -> b) -> a -> b 
f $ x = f x 

Cho đến nay mọi thứ đều rõ ràng. Tôi hiểu tất cả các ví dụ trong phần này, trừ trường hợp mới nhất:

ghci> map ($ 3) [(4+), (10*), (^2), sqrt] 
[7.0,30.0,9.0,1.7320508075688772] 

Ở đây chúng ta bản đồ ($ 3) qua danh sách các chức năng và nhận được kết quả của việc áp dụng những chức năng để 3. Nhưng làm thế nào điều này có thể?

Từ mã đầu tiên đoạn mã thì rõ ràng rằng số đầu tiên là một chức năng, chúng tôi thậm chí có thể viết:

*Main> ($) sqrt 4 
2.0 

Bây giờ ($ 3) là một ứng dụng phần chức năng $, nhưng 3 đi vào vị trí chức năng của! Vì vậy, 3 được coi là một chức năng hay gì?

Có một bí ẩn khác: cái quái gì là (4+)? Tôi biết rằng (+4) là một ứng dụng một phần chức năng +, vì vậy (4+) nên được áp dụng một phần chức năng 4? Vô lý. Loại thủ thuật nào hoạt động ở đây?

+0

bản sao có thể có của [Ứng dụng một phần với chức năng Infix] (http://stackoverflow.com/questions/10131300/partial-application-with-infix-functions) – Lambdageek

Trả lời

12

($ 3)(+ 4) không ứng dụng phần - chúng phận điều hành. Một phần ứng dụng sẽ trông giống như (($) 3) hoặc ((+) 4).

Một phần tử của mẫu (? x) (nơi ? đứng cho một nhà điều hành ghi tùy ý) liên kết với các toán hạng đúng của các nhà điều hành, tức là nó tương đương với \y -> y ? x.Tương tự, toán tử (x ?) liên kết toán hạng bên trái và do đó tương đương với một phần ứng dụng.

6

Tôi nghĩ rằng những gì bạn đang vấp ngã là các toán tử. Điều này cho phép bạn áp dụng một phần toán tử với một trong các đối số của nó, vì vậy bạn có thể có toán tử (+4)(4+), trong đó 4 là đối số thứ hai, sau đó đối số đầu tiên là + tương ứng. Một ví dụ rõ ràng hơn có thể là ("Hello" ++) so với (++ "world"), trước đây là chi tiết "Hello" vào mặt trước của một chuỗi, trong khi sau đó gắn thêm "world" vào cuối chuỗi.

Điều này được tương phản với việc sử dụng toán tử ở dạng tiền tố chỉ với số lần quay xung quanh nó. Trong biểu mẫu này, các thông tin sau đây tương đương:

> let join = (++) 
> join "Hello, " "world" 
"Hello, world" 
> (++) "Hello, " "world" 
"Hello, world" 

Ở dạng tiền tố, bạn coi toán tử là hàm bình thường và chấp nhận đối số thứ hai và thứ hai theo thứ tự. Trong các toán tử, nó quan trọng bên nào của toán tử đối số được bật.


Vì vậy, trong ví dụ của bạn, bạn phải áp dụng một phần của ($ 3), bạn có thể giảm nó như

map ($ 3) [(4+), (10*), (^2), sqrt] 
[($ 3) (4+), ($ 3) (10 *), ($ 3) (^ 2), ($ 3) sqrt] 
[4 + 3, 10 * 3, 3^2, sqrt 3] 
[7.0, 30.0, 9.0, 1.7320508075688772] 
+0

"bạn coi toán tử là hàm bình thường", tôi nghĩ 'toán tử' * là * các hàm bình thường trong Haskell. – Mark

+1

@Mark chúng bình thường ở mọi khía cạnh khác với cú pháp của chúng cho ứng dụng. Chúng theo mặc định, trong khi một hàm phi toán tử là tiền tố mặc định. Khi tôi nói hàm bình thường, tôi có nghĩa là một hàm tiền tố. – bheklilr

4

Bạn đang bị nhầm lẫn với các phần. Một cách hay để nắm bắt khái niệm các phần là chơi với một ví dụ:

(<^>) :: Int -> Float -> Int 
a <^> b = a 

Hàm trên là hàm vô dụng trả về tham số đầu tiên cho dù tham số thứ hai là gì. Nhưng nó chấp nhận Int và sau đó là Float làm đầu vào.

Bây giờ, vì các bộ phận bạn có thể áp dụng với bất kỳ một trong những lập luận của họ:

λ> let a = (3 <^>) 
λ> :t a 
a :: Float -> Int 
λ> let b = (<^> 3.0) 
λ> :t b 
b :: Int -> Int 

Xem cách loại ab là khác nhau vì các bộ phận.

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