Một ví dụ thực tế của việc sử dụng chức năng cà ri? [đóng cửa]


8

Tôi đã vật lộn để tìm một ví dụ thực tế về việc sử dụng chức năng cà ri và nhận được lợi ích của việc sử dụng cà ri.

Khi tôi google chức năng cà ri tôi thường thấy ví dụ như

let add = x => y => x + y;
let add10 = add(10);
console.log(add10(20));

Tôi phải nói rằng tôi thực sự không thấy giá trị của việc sử dụng cà ri trong ví dụ này.

Sau khi đọc qua các câu trả lời trong SO /programming/113780/javascript-curry-what-are-the-pratics-appluggest Tôi vẫn không thấy lợi ích của việc sử dụng nó.

Ví dụ, câu trả lời điểm cao nhất đưa ra một ví dụ về trình chuyển đổi, nhưng ví dụ đó có thể được viết lại mà không có cà ri như một câu trả lời khác cho thấy.

Tôi cũng đọc qua các câu trả lời Ưu điểm của cà ri là gì? (mặc dù cuộc thảo luận không giới hạn với javascript) Tôi vẫn có cảm giác rằng phiên bản cà ri có thể được viết lại mà không có cà ri (trong js).

Vậy ai đó có thể chỉ cho tôi lợi thế / lợi ích "thực sự" của việc sử dụng cà ri trong javascript không?

---- cập nhật ----

Ngoại trừ các câu trả lời tôi nhận được tôi cũng tìm thấy ví dụ nhật ký ở đây cho thấy lợi ích của việc sử dụng nó.



2
Tôi đồng ý rằng hầu hết các ví dụ cơ bản về cà ri mà bạn tìm thấy trên mạng là cực kỳ ấn tượng.
dùng949300

@ user949300 BTW, tôi thực sự không hiểu tại sao câu hỏi của tôi lại bị bỏ phiếu. Không phải là một câu hỏi "hợp lệ" khi bạn nghĩ về cà ri js? Tôi đã lo lắng nó sẽ bị đóng cửa tại SO nên tôi đã hỏi ở đây. :(
Qiulang

Tôi thấy currying hầu như hữu ích khi một hàm lib bên ngoài mong đợi một hàm (ví dụ như gọi lại) có một số lượng đối số nhất định và bạn có một hàm (ví dụ: trình xử lý) có nhiều đối số hơn, nhưng bạn muốn truyền các giá trị không đổi cho các đối số bổ sung này. Bản sao một phần sau đó dễ đọc hơn chức năng mũi tên
tutuDajuju

3
"Tôi vẫn có cảm giác rằng phiên bản cà ri có thể được viết lại mà không có cà ri" - Đây là một thứ tầm thường, vì đó là tất cả những gì về cà ri. Toàn bộ điểm của currying là quan sát rằng bất kỳ chức năng nào của n tham số có thể được viết lại dưới dạng hàm của tham số n-1 trả về một hàm lấy tham số thứ n. Cũng lưu ý rằng tuyên bố này là đúng với khá nhiều thứ. Mỗi forvòng lặp có thể được viết lại như một whilevòng lặp. Mỗi ifcâu lệnh có thể được viết lại như một whilevòng lặp. Mỗi whilevòng lặp có thể được viết lại như một goto. Điều đó không có nghĩa là chúng không hữu ích.
Jörg W Mittag

Câu trả lời:


8

Tôi hầu như không bao giờ sử dụng Currying, nhưng đây là một ví dụ gần đây, nơi nó tỏ ra hữu ích. Tôi đã viết mã cho trò chơi Battlesnake , nhưng điều này sẽ áp dụng cho nhiều trò chơi. Họ cung cấp cho bạn các mảng khác nhau, đưa ra vị trí của con rắn, rắn của bạn và thức ăn. Giả sử bạn đang xem xét việc chuyển đến một điểm {x, y} nhất định và bạn muốn kiểm tra xem nó có chứa một con rắn khác, thức ăn hay thậm chí là chính bạn không. Vượt qua đầu tiên sẽ là viết mã như thế này (Tôi sẽ sử dụng kết hợp chức năng và mũi tên răng nanh mới)

// utility function
function samePoint(p1, p2) {
  return (p1.x === p2.x) && (p1.y === p2.y);
}

và một nơi nào đó trong mã đi

let possibleMove = {x,y}; // where you are thinking of moving
...
if (foodArray.some((p) => samePoint(p, possibleMove )) {
  // this move looks tasty, give it a bonus value...
}

Không tệ, nhưng, vì bạn sẽ làm điều này nhiều nơi trong mã của bạn, một chút tẻ nhạt và vụng về. Và, từ kinh nghiệm của tôi, dễ làm rối tung hai cuộc cãi vã. :-( Vấn đề cơ bản là some()(hoặc find()) chấp nhận một hàm chỉ lấy một đối số duy nhất và bạn thực sự cần hai đối số , hai điểm. Vì vậy, bạn nghĩ đến việc currying! Ở đây nhiều người sẽ sử dụng các mũi tên, tôi thấy các hàm lồng nhau rõ ràng hơn:

function samePointAs(p1) {
  return function(p2) {
    return samePoint(p1, p2);
  }
}

Sau đó, bài kiểm tra "là thực phẩm" của bạn trở thành

let possibleMove = {x,y}; // where you are thinking of moving
...
if (foodArray.some(samePointAs(possibleMove )) {
  // this move looks tasty, give it a bonus value...
}

Đây có phải là sẽ làm cho bạn một triệu phú Internet? Chắc là không. Nhưng nó đơn giản hóa, và trong trường hợp này, làm rõ mã của bạn.


Xin chào Tôi thích bạn ví dụ vì vậy tôi đã đánh dấu câu trả lời của bạn là câu trả lời được chấp nhận. Cảm ơn.
Qiulang

Xin chào, câu hỏi của tôi được giữ lại. Nó thậm chí còn có một phiếu bầu xóa. Tôi đã cố gắng chỉnh sửa nó để làm cho nó bị trì hoãn mà không có kết quả. Tôi đã tự hỏi bạn có thể giúp tôi chỉnh sửa nó?
Qiulang

14

Curry trong ví dụ của bạn không thực sự có ý nghĩa, tôi đồng ý. Để xem chức năng của currying, bạn cần kết hợp nó với các hàm bậc cao hơn: các hàm lấy các hàm khác làm tham số.

Ví dụ điển hình nhất về điều này là bản đồ, bộ lọc và thu nhỏ, mặc dù một tình huống phổ biến khác là gọi lại. Khi bạn áp dụng một phần chức năng, bạn có thể chuyển chức năng được áp dụng một phần cho các chức năng bậc cao này. Currying có ý nghĩa khi hầu hết thời gian bạn muốn sử dụng một chức năng là dành cho một ứng dụng một phần để nó có thể được chuyển sang một chức năng bậc cao khác.

Một ví dụ minh họa hơn có thể trông giống như vậy:

let array1 = [1, 4, 9, 16];
let add = x => y => x + y;
array2 = array1.map(foo ? add(10) : add(20));

Curry không bao giờ là cần thiết, vâng, vì bạn luôn có thể tạo chức năng ẩn danh / mũi tên từ một chức năng thông thường khi bạn cần, nhưng trong một số trường hợp, có thể rất thuận tiện để có chức năng quấy rối so với thông thường (và trong các tình huống khác, đó chỉ là làm cho mọi thứ gây phiền nhiễu và chậm chạp).


2
"nhưng trong một số tình huống có thể rất thuận tiện khi có chức năng quấy rối so với thông thường", vậy bạn có thể đưa ra một số ví dụ về điều đó không? Cảm ơn!
Qiulang

@Qiulang một ví dụ là nếu bạn có một loạt logic cấu hình điều khiển cách gọi một hàm có nhiều tham số. Nếu bạn không có chức năng quấy rối, bạn thường phải tạo một đối tượng có API thông thạo hoặc cung cấp một số phương thức clone_and_update () hoặc bạn sẽ phải tạo một lớp Builder riêng để xây dựng tham số hàm Từng bước. Một ví dụ điển hình cho việc này là trình tạo truy vấn của ORM. Với chức năng curried, bạn chỉ có thể gọi hàm như bình thường trên mỗi bước.
Lie Ryan

@LieRyan Trong JavaScript , nơi rất đơn giản để tạo một "đối tượng" tùy chọn bằng cách sử dụng {}, tôi không thấy các lớp Builder là rất hữu ích hoặc phổ biến. Bạn có thể trích dẫn một số ví dụ?
dùng949300

1
@ user949300 Tạo hai mươi đối tượng với mười thành viên chỉ khác nhau bởi một hoặc hai tham số không dễ dàng hơn trong bất kỳ ngôn ngữ nào khác. Với đối tượng trình xây dựng bất biến sử dụng giao diện lưu loát, thay vào đó, bạn có thể xây dựng đối tượng cấu hình cơ sở sau đó chỉ cần phân nhánh để tạo các bộ đối số khác nhau. Kiểu mẫu này thường có thể trông quá nặng trong mã ứng dụng, nhưng nó khá phổ biến đối với các tác giả thư viện / khung.
Lie Ryan

1
Đã lấy điểm, nhưng @LieRyan với tính năng mới Object.assign(), việc phân nhánh cấu hình cơ sở khá dễ dàng.
dùng949300
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.