Curry function là gì? Một món "cà ri" ngon và làm sao để thưởng thức nó?

  • 0

  • 0

  • 0

Curry function là gì? Một món "cà ri" ngon và làm sao để thưởng thức nó?

Curry function là gì? Một món "cà ri" ngon và làm sao để thưởng thức nó?

Vấn đề

Đối với mỗi lập trình viên, việc viết một đoạn mã có thể sử dụng lại nhiều lần là điều luôn cần thiết. Mỗi người có những cách để hiện thực hoá chúng, ví như việc đóng thư viện các đoạn mã hữu ích chẳng hạn. Nhưng trong bài viết này chúng ta hãy nói ở tầm vi mô hơn đó là ở mức độ hàm.

Curry function là gì?

Khái niệm về curry function khá là đơn giản, nó chính là một hàm javascript bình thường trong đó nhận nhiều đối số bằng một loạt các hàm một đối số. Ví dụ:

function sum(a) {
  return function add(b) {
    return a + b;
  }
}

const add1 = sum(1);
const result = add1(2);
console.log(result); // 3;

// Hoặc ngắn gọn hơn chúng ta cũng có thể viết:  
const result =  sum(1)(2);
console.log(result); // 3

Oh, cú pháp có vẻ lơi lạ lẫm ha. Vậy thì điều này mang lại lợi ích gì?

Tại sao lại curry function?

Có 2 điều mà curry function có thể mang lại:

  • Các hàm nhỏ hơn có thể diễn dãi vấn đề một cách rõ ràng hơn và tái sử dụng lại một cách dễ dàng, không lộn xộn
  • Các hàm được sử dụng xuyên suốt

Hãy để tôi ví dụ cho các bạn làm rõ 2 điều trên.

Các hàm nhỏ hơn diễn đạt tốt hơn

Ví dụ đầu tiên tôi có một mảng các đối tượng gồm có id và name, hãy lấy ra chỉ mỗi id:

const objects = [{ id: 1, name: "A" }, { id: 2, name: "B" }, { id: 3, name: "C" }];
const ids = objects.map(function (o) { return o.id; });

Thật đơn giản phải không? Nhưng có một vấn để ở đây function (o) { return o.id; } là đủ nhưng chưa tốt. Hãy làm cho nó tốt hơn:

function get(attr) {
  return function getAttr(obj) {
    return obj[attr];
  }
}
const ids = objects.map(get("id"));

get là một hàm curry, nó nhận vào một attr để phục vụ việc việc lấy ra attribute nào và một obj là đối tượng cần được lấy ra.

Có thể bạn sẽ cảm thấy hơi khó hiểu với cách viết ở ids kia, hãy nhớ lại hàm map của javascript một chút:

Array.map(function (i) { return i; });

.map nhận vào tham số là một hàm, hàm này có quyền truy cập vào mỗi phần tử trong mảng để xử lý.

Hay nói cách khác đây thực sự là những gì mà ids được làm:

const ids = objects.map(function (o) { return get("id")(o); });

Đến đây thì các bạn đã hiểu rồi chứ? Vậy thì tôi có một câu hỏi dành cho bạn: nếu như tôi muốn dùng lại hàm "lấy id ra khỏi objects" kia nhiều lần thì sẽ làm như thế nào? Có phải là như thế này:

function getIds(objs) {
  return objects.map(get("id"));
}

getIds(objects);

Chà có vẻ mọi thứ hoạt động, tuy nhiên nó vẫn có thể tốt hơn. Tại sao chúng ta không áp dụng curry function để tạo ra một hàm được gọi là "map" có tác dụng lặp qua các phần tử trong mảng?

function map(func) {
  return function exec(value) {
    return value.map(func);
  }
}

function getIds = map(get("id"));
getIds(objects);

Đến đây thì tôi thấy rằng, nếu các hàm cơ bản là curry thì tôi có thể dễ dàng tạo ra một hàm thực hiện một chức năng mới từ chúng. Và một điều nữa là đoạn mã được viết rất dễ đọc, nhìn vào biết ngay là làm gì.

Chức năng xuyên suốt

Một ưu điểm của curry function là nó cho phép mã của bạn tập trung vào chức năng của nó hơn là một hàm thông thường. Như ở các ví dụ trên, việc tạo ra các hàm map, get, getIds giúp các đoạn mã dễ đọc hơn vì nó phản ánh đúng nhiệm vụ mà nó sẽ làm.

Hãy xem xét một ví dụ: Tôi có một hàm lấy dữ liệu JSON từ một máy chủ là fetchData, đây là một hàm bất đồng bộ và sau khi nhận được phản hồi, tôi sẽ lấy ra posts và danh sách id của các posts.

fetchData()
  .then(JSON.parse)
  .then(function(data){ return data.posts })
  .then(function(posts){
    return posts.map(function(post){ return post.title })
  });

Có thể bạn sẽ có cách viết khác tôi, nhưng trong trường hợp này tôi muốn nhấn mạnh việc sử dụng curry function sẽ làm đoạn mã kia trông dễ hiểu hơn:

fetchData()
  .then(JSON.parse)
  .then(get("posts")
  .then(map(get("id")));

Vì lợi ích mang lại của curry function, cũng có khá là nhiều những thư viện hỗ trợ như curry, hàm curry của Ramda là một thư viện nổi tiếng cho lập trình hàm.

Tổng kết

Curry function là một cách để "chơi" với hàm, diễn dãi hàm một cách dễ hiểu với những lợi ích mà nó mang lại. Ngay từ bây giờ nếu bạn cảm thấy hứng thú thì hãy thử áp dụng nó vào trong dự án tiếp theo của mình.

Bạn thấy bài viết này có ích?
  • Không

  • Bình thường

Bình luận
DMCA.com Protection Status