2015-09-23 25 views
11

Tôi đã đọc rất nhiều bài viết về cà ri, nhưng hầu như tất cả chúng đều gây hiểu nhầm, giải thích việc sử dụng curry như một ứng dụng chức năng một phần và tất cả các ví dụ thường là về các chức năng với số 2, chẳng hạn như hàm add.Trường hợp sử dụng thực tế của cà ri là gì?

Cũng có nhiều triển khai của curry hàm trong JavaScript làm cho nó chấp nhận hơn 1 tham số cho mỗi ứng dụng một phần (xem lodash), khi Wikipedia article nói rõ currying đó là về:

dịch đánh giá của một hàm lấy nhiều đối số (hoặc một bộ đối số) để đánh giá một chuỗi các hàm, mỗi đối số có một tham số đơn lẻ (một phần ứng dụng)

Vì vậy, việc xử lý cơ bản là một loạt các ứng dụng từng phần với một đơn rgument. Và tôi thực sự muốn biết cách sử dụng thực sự của điều đó, bằng bất kỳ ngôn ngữ nào.

+0

Điều gì khiến bạn nghĩ rằng các cách sử dụng khác của cụm từ này là "sai"? – dfeuer

Trả lời

7

Trường hợp sử dụng thực tế của currying là một phần ứng dụng.

Việc tự mài không phải là điều thú vị. Điều thú vị là nếu ngôn ngữ lập trình của bạn hỗ trợ currying theo mặc định, như trường hợp trong F # hoặc Haskell.

Bạn có thể xác định các hàm bậc cao hơn cho currying và ứng dụng một phần bằng bất kỳ ngôn ngữ nào hỗ trợ chức năng lớp đầu tiên, nhưng nó không khác gì tính linh hoạt bạn nhận được khi mọi chức năng bạn nhận được đều được áp dụng. làm bất cứ gì. Vì vậy, nếu bạn thấy mọi người conflating currying và một phần ứng dụng, đó là vì các khái niệm đó được gắn chặt như thế nào - vì currying có mặt khắp mọi nơi, bạn không thực sự cần các dạng ứng dụng khác hơn là áp dụng các hàm curried cho các đối số liên tiếp.

+3

Là một người đã ở vị trí của OP và gần đây đã đến để xem sự hấp dẫn của cà ri, tôi không thể đồng ý hơn với câu trả lời này. Sau khi đọc https://drboolean.gitbooks.io/mostly-adequate-guide/content/ch4.html và http://ramdajs.com/0.17/docs/#curry, mọi thứ có ý nghĩa! Đó là tất cả về việc có tất cả các chức năng curried theo mặc định, mở ra cánh cửa để sử dụng một phần chức năng được áp dụng như 'xây dựng các khối' trong mã của bạn. – TW80000

4

Thật hữu ích khi vượt qua ngữ cảnh.

Hãy xem xét chức năng 'bản đồ'. Phải mất một chức năng như là đối số:

map : (a -> b) -> [a] -> [b] 

Cho một chức năng trong đó sử dụng một số hình thức của bối cảnh:

f : SomeContext -> a -> b 

này có nghĩa là bạn thanh lịch có thể sử dụng chức năng bản đồ mà không cần phải nêu rõ 'a'đối số :

map (f actualContext) [1,2,3] 

Nếu không tách lạng bộ, bạn sẽ phải sử dụng một lambda:

map (\a -> f actualContext a) [1,2,3] 

Ghi chú:

map là một chức năng mà phải mất một danh sách có chứa các giá trị của a, một chức năng f. Nó tạo danh sách mới bằng cách lấy mỗi a và áp dụng f cho nó, dẫn đến danh sách b

ví dụ: map (+1) [1,2,3] = [2,3,4]

1

Vòng bi có trên mã có thể được chia thành hai bộ vấn đề (tôi sử dụng Haskell để minh họa). Cú pháp thực thi.

Cú pháp Issue 1:

tách lạng bộ cho phép rõ ràng đang lớn hơn trong một số trường hợp. Độ rõ ràng là gì? Đọc chức năng cung cấp dấu hiệu rõ ràng về chức năng của nó. ví dụ: Chức năng bản đồ.

map : (a -> b) -> ([a] -> [b]) 

đọc theo cách này, chúng ta thấy rằng bản đồ là một hàm bậc cao mà thang máy một chức năng chuyển as-bs đến một chức năng cho phép bạn biến [a]-[b].

Trực giác này đặc biệt hữu ích khi hiểu các biểu thức như vậy.

map (map (+1)) 

Bản đồ bên trong có loại trên [a] -> [b]. Để tìm ra loại bản đồ bên ngoài, chúng tôi đệ quy áp dụng trực giác của chúng tôi từ trên cao. Bản đồ bên ngoài do đó nâng cao [a] -> [b] đến [[a]] -> [[b]].

Trực giác này sẽ đưa bạn chuyển tiếp LOT. Khi chúng tôi khái quát map thành fmap, một map trên các thùng chứa tùy ý, nó trở nên rất dễ đọc các biểu thức như vậy (Lưu ý tôi đã định hình loại mỗi fmap thành một loại khác vì lợi ích của ví dụ).

showInt : Int -> String 
(fmap . fmap . fmap) showInt : Tree (Set [Int]) -> Tree (Set [String]) 

Hy vọng điều trên minh họa rằng khái niệm khái quát về việc nâng hàm vani vào các chức năng trên một số thùng chứa tùy ý.

Cú pháp Vấn đề 2:

tách lạng bộ cũng cho phép chúng ta thể hiện chức năng ở dạng point-miễn phí.

nthSmallest : Int -> [Int] -> Maybe Int 
nthSmallest n = safeHead . drop n . sort 

safeHead (x:_) = Just x 
safeHead _  = Nothing 

Ở trên thường được coi là phong cách tốt vì nó minh họa suy nghĩ về đường ống chức năng hơn là thao tác rõ ràng dữ liệu.

Thực hiện:

Trong Haskell, điểm phong cách tự do (thông qua currying) có thể giúp chúng tôi tối ưu hóa các chức năng. Viết một hàm ở dạng tự do điểm sẽ cho phép chúng ta ghi nhớ nó.

memoized_fib :: Int -> Integer 
memoized_fib = (map fib [0 ..] !!) 
    where fib 0 = 0 
      fib 1 = 1 
      fib n = memoized_fib (n-2) + memoized_fib (n-1) 


not_memoized_fib :: Int -> Integer 
not_memoized_fib x = map fib [0 ..] !! x 
    where fib 0 = 0 
      fib 1 = 1 
      fib n = not_memoized_fib (n-2) + not_memoized_fib (n-1) 

Viết nó như là một chức năng được ghi lại trong phiên bản ghi nhớ xử lý chức năng được kết hôn làm thực thể và do đó ghi nhớ nó.

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