12

Mặc dù tôi hiểu một chút về cách nghiền theo nghĩa toán học, một phần áp dụng chức năng trộn là một khái niệm mới mà tôi phát hiện sau khi lặn vào cuốn sách Learn You a Haskell for Great Good.Ứng dụng một phần với chức năng Infix

Với chức năng này:

applyTwice :: (a -> a) -> a -> a 
applyTwice f x = f (f x) 

Tác giả sử dụng nó trong một cách thú vị:

ghci> applyTwice (++ [0]) [1] 
[1,0,0] 
ghci> applyTwice ([0] ++) [1] 
[0,0,1] 

Ở đây tôi có thể thấy rõ rằng chức năng kết quả là có thông số khác nhau trôi qua, trong đó sẽ không xảy ra bằng cách bình thường có nghĩa là xem xét nó là một curited chức năng (phải không?). Vì vậy, có bất kỳ điều trị đặc biệt trên phân đoạn infix bởi Haskell? Là nó chung chung với tất cả các chức năng infix?


Như một mặt lưu ý, đây là tuần đầu tiên của tôi với Haskell và lập trình chức năng, và tôi vẫn đang đọc sách.

Trả lời

18

Có, bạn có thể áp dụng một phần toán tử infix bằng cách chỉ định toán hạng trái hoặc phải, chỉ cần bỏ trống toán tử còn lại (chính xác trong hai ví dụ bạn đã viết).

Vì vậy, ([0] ++) cũng giống như (++) [0] hoặc \x -> [0] ++ x (nhớ bạn có thể biến một nhà điều hành ghi vào một chức năng tiêu chuẩn bằng ngoặc đơn), trong khi (++ [0]) tương đương với \x -> x ++ [0].

Nó rất hữu ích để biết còn việc sử dụng backticks, (``), cho phép bạn biến bất kỳ chức năng tiêu chuẩn với hai đối số trong một nhà điều hành ghi:

Prelude> elem 2 [1,2,3] 
True 
Prelude> 2 `elem` [1,2,3] -- this is the same as before 
True 
Prelude> let f = (`elem` [1,2,3]) -- partial application, second operand 
Prelude> f 1 
True 
Prelude> f 4 
False 
Prelude> let g = (1 `elem`) -- partial application, first operand 
Prelude> g [1,2] 
True 
Prelude> g [2,3] 
False 
+0

Vì vậy, tôi không biết Haskell, nhưng là '(1 \' elem \ ')' giống như '1' elem? – Neil

+1

@Neil: Vâng, đúng vậy. –

+4

Tôi thích nghĩ về '(++)' như một phần mà bạn bỏ qua cả hai đầu vào. –

5

Tất cả các nhà khai thác trung tố có thể được sử dụng trong các phần trong Haskell - ngoại trừ - do sự kỳ lạ với sự phủ nhận đơn nhất. Điều này thậm chí còn bao gồm các chức năng không được chuyển đổi thành infix bằng cách sử dụng backticks. Bạn thậm chí có thể nghĩ đến việc xây dựng để làm nhà khai thác vào các chức năng bình thường như một hai mặt phần:

(x + y) ->(+ y) ->(+)

mục được (chủ yếu là, với một số trường hợp góc hiếm) được coi là lambdas đơn giản. (/ 2) là giống như:

\x -> (x/2)

(2 /) cũng giống như \x -> (2/x), cho một ví dụ với một nhà điều hành không giao hoán.

Không có gì thú vị về mặt lý thuyết khi diễn ra ở đây. Nó chỉ là cú pháp cú pháp để áp dụng một phần các toán tử infix. Nó làm cho mã một chút đẹp hơn, thường xuyên. (Có tất cả các mẫu đối kháng.)

+2

Lưu ý rằng "sự kỳ lạ với sự phủ định đơn nhất" là do thực tế là nó không rõ ràng cho dù '(- 1)' nên được hiểu là số nguyên -1 hay là hàm '\ x -> x - 1'. Sự lựa chọn của những người sáng tạo của Haskell là để giải thích nó như là một chữ số, và cung cấp hàm 'subtract', đáp ứng' trừ x = \ y -> y - x'. Chúng cũng cung cấp 'negate' hoạt động như hàm trừ đơn nhất, tức là' negate x = -x' –

+0

@ChrisTaylor: Hầu như. '(- x)' dịch thành 'phủ định x', vì vậy' (- 1) 'là' negate (fromInteger 1) ', không phải' fromInteger (-1) '. Tất nhiên, cả hai nên tương đương với các trường hợp 'Num' hoạt động tốt. – hammar

+0

@hammar Ah ok, có chút logic ngược ở đó. Cảm ơn vì sự đúng đắn của bạn! –

15

Có, đây là the section syntax tại nơi làm việc.

Các phần được viết là (op e) hoặc (e op), trong đó op là toán tử nhị phân và e là biểu thức. Các phần là một cú pháp thuận tiện cho việc áp dụng một phần các toán tử nhị phân.

Các sắc sau giữ:

(op e) = \ x -> x op e 
(e op) = \ x -> e op x