2015-05-25 15 views
6

Reading http://www.seas.upenn.edu/~cis194/spring13/lectures/04-higher-order.html nó khẳng địnhTính hữu ích của "mũi tên chức năng liên kết với bên phải"?

Đặc biệt, lưu ý rằng mũi tên chức năng sư bên phải, mà là, W -> X -> Y -> Z tương đương với W -> (X -> (Y -> Z)). Chúng tôi có thể luôn thêm hoặc xóa dấu ngoặc đơn quanh mũi tên cấp cao nhất bên phải trong một loại.

Mũi tên chức năng liên kết với bên phải nhưng dưới dạng ứng dụng chức năng liên kết với bên trái thì tính hữu ích của thông tin này là gì? Tôi cảm thấy tôi không hiểu điều gì đó đối với tôi, đó là một điểm vô nghĩa mà mũi tên chức năng liên kết với bên phải. Như ứng dụng chức năng luôn luôn liên kết với bên trái thì đây là mối liên kết duy nhất tôi nên quan tâm?

Trả lời

13

Mũi tên chức năng liên kết với bên phải nhưng [...] Tính hữu ích của thông tin này là gì?

Nếu bạn thấy một loại chữ ký như thế nào, ví dụ, f : String -> Int -> Bool bạn cần phải biết kết hợp của các chức năng mũi tên để hiểu những gì các loại f thực sự là:

  1. nếu cộng mũi tên bên trái, sau đó loại có nghĩa là (String -> Int) -> Bool, nghĩa là, f lấy hàm làm đối số và trả về một boolean.
  2. nếu mũi tên liên kết sang phải, thì loại có nghĩa là String -> (Int -> Bool), nghĩa là, f lấy chuỗi làm đối số và trả về hàm.

Đó là sự khác biệt lớn và nếu bạn muốn sử dụng f, bạn cần phải biết nó là cái nào. Vì mũi tên hàm liên kết bên phải, bạn biết rằng nó phải là tùy chọn thứ hai: f lấy một chuỗi và trả về một hàm.

Chức năng mũi tên sư sang bên phải [...] ứng dụng chức năng cộng bên trái

Hai lựa chọn làm việc tốt với nhau. Ví dụ: chúng tôi có thể gọi số f từ bên trên là f "answer" 42 thực sự có nghĩa là (f "answer") 42. Vì vậy, chúng tôi đang chuyển chuỗi "answer" đến f trả về một hàm. Và sau đó chúng tôi đang chuyển số 42 đến hàm đó, trả về một boolean. Thực tế, chúng ta gần như đang sử dụng f như một hàm với hai đối số.

Đây là cách viết chuẩn của hàm với hai (hoặc nhiều) đối số trong Haskell, vì vậy đây là trường hợp sử dụng rất phổ biến. Do sự kết hợp của ứng dụng hàm và của mũi tên hàm, chúng ta có thể viết trường hợp sử dụng phổ biến này mà không có dấu ngoặc đơn.

+2

Điều này cũng giúp bạn suy nghĩ về kỹ thuật hữu ích của [currying] (https://en.wikipedia.org/wiki/Currying), nhờ đó chúng tôi sử dụng hàm _function_ thực tế được trả về. Ví dụ, nếu chúng ta có một số 'fxy: Int -> Int -> Int' đã tính' x * y', thì chúng ta có thể sử dụng 'f 2' như một hàm" tăng gấp đôi ", của' f 3' là một "gấp ba" "chức năng vv – csey

5

Khi xác định một hàm cà ri hai cãi nhau, chúng tôi thường viết một cái gì đó như thế này:

f :: a -> b -> c 
f x y = ... 

Nếu mũi tên không liên kết ở bên phải, loại trên sẽ thay phải được nêu ra như a -> (b -> c). Vì vậy, tính hữu dụng của sự kết hợp của -> là nó giúp chúng ta ghi lại quá nhiều dấu ngoặc đơn khi khai báo các kiểu hàm.

1

Nếu một nhà điều hành # là 'kết hợp đúng', nó có nghĩa này:

a # b # C# d = a # (b # (C# d)) 

... cho bất kỳ số lượng đối số. Nó hoạt động như foldr

Điều này có nghĩa rằng:

a -> b -> c -> d = a -> (b -> (c -> d)) 

Lưu ý: a -> (b -> (c -> d)) =/= ((a -> b) -> c) -> d! Cái này rất quan trọng.

Điều này cho chúng ta biết là, nói, foldr:

λ> :t foldr 
foldr :: (a -> b -> b) -> b -> [a] -> b 

Mất một chức năng của loại (a -> b -> b), và sau đó trả về ... một chức năng mà phải mất một b, và sau đó trả về ... một chức năng mất một [a], và sau đó trả về ... một b. Điều này có nghĩa rằng chúng ta có thể áp dụng các chức năng như thế này

f a b c 

f a b c = ((f a) b) c 

f sẽ trở lại hai chức năng mỗi lần cãi nhau được đưa ra.

Về cơ bản, đây không phải là hữu ích như vậy, nhưng là thông tin quan trọng khi chúng tôi muốn diễn giải và gọi các loại chức năng.

Tuy nhiên, trong các chức năng như (++), các vấn đề liên quan. Nếu (++) được liên kết trái, nó sẽ rất chậm, vì vậy nó là kết hợp đúng.

+0

(++) ứng dụng chức năng liên kết bên phải, có tác động hiệu quả như bạn đề cập và do đó là thông tin hữu ích. Sự kết hợp của các mũi tên là vô nghĩa và không sử dụng như ứng dụng chức năng là tất cả những gì quan trọng? –

+1

'Tuy nhiên, trong các chức năng như (++), các vấn đề kết hợp. Nếu (++) đã được trái kết hợp, nó sẽ rất chậm, vì vậy nó là kết hợp đúng. Đó là một chút của một tuyên bố gây hiểu lầm. Nếu tôi có một cái gì đó như 'a ++ b ++ c' có một cách nhanh chóng để ngoặc đơn nó và một cách chậm. Khả năng tương tác ảnh hưởng đến cái nào được chọn * nếu tôi không tự lồng ghép chính nó *, nhưng nó không ảnh hưởng đến tốc độ của chính hàm đó. Nếu tôi hoàn toàn ngoặc đơn việc sử dụng toán tử của mình, thì tính kết hợp không có tác dụng gì cả. – sepp2k

+4

@ blue-sky 'a -> (b -> c)' là một kiểu rất khác với '(a -> b) -> c', vì vậy khi bạn viết' a -> b -> c', nó không phải vô nghĩa ở tất cả những gì liên kết của '->' là. – sepp2k

0

Ngôn ngữ hàm ban đầu Lisp bị quá nhiều dấu ngoặc đơn (làm cho mã (hoặc thậm chí văn bản (nếu bạn không nhớ xem xét ngữ cảnh rộng hơn)) khó đọc. đọc và viết cho thuận ngay cả với chi phí của các tân binh khó hiểu với các quy tắc thống nhất ít hơn

Trong mã chức năng, khai báo kiểu hàm như (String -> Int) -> Bool hiếm hơn nhiều so với các hàm như String -> (Int -> Bool), bởi vì hàm trả về hàm là dấu thương mại của kiểu hàm, do đó các mũi tên liên kết bên phải giúp giảm số dấu ngoặc đơn (khi khai thác, bạn có thể cần ánh xạ hàm thành kiểu nguyên thủy). -versa.

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