Phong cách "điểm tự do" (trong Lập trình chức năng) là gì?


100

Một cụm từ mà tôi nhận thấy gần đây là khái niệm về phong cách "point free" ...

Đầu tiên, có câu hỏi này , và cũng là câu hỏi này .

Sau đó, tôi phát hiện ra ở đây họ đề cập đến "Một chủ đề khác có thể đáng thảo luận là việc các tác giả không thích phong cách tự do điểm."

Phong cách "điểm miễn phí" là gì? Ai đó có thể đưa ra một lời giải thích ngắn gọn? Nó có liên quan gì đến cách nấu cà ri "tự động" không?

Để có được ý tưởng về trình độ của mình - tôi đã tự học về Scheme, và đã viết một trình thông dịch Đề án đơn giản ... Tôi hiểu cà ri "ngầm" là gì, nhưng tôi không biết bất kỳ Haskell hay ML nào.


3
Chỉ cần một lưu ý: để xem lý do tại sao nó được gọi là pointfree lần Pointfree / Nhưng pointfree có nhiều điểm hơn! tại HaskellWiki.
Petr Pudlák

Câu trả lời:


66

Chỉ cần xem bài viết trên Wikipedia để biết định nghĩa của bạn:

Lập trình Tacit (lập trình không điểm) là một mô hình lập trình trong đó định nghĩa hàm không bao gồm thông tin liên quan đến các đối số của nó, sử dụng tổ hợp và thành phần hàm [...] thay vì các biến.

Ví dụ về Haskell:

Thông thường (bạn chỉ định các đối số một cách rõ ràng):

sum (x:xs) = x + (sum xs)
sum [] = 0

Không có dấu chấm ( sumkhông có bất kỳ đối số rõ ràng nào - nó chỉ là một phần với +bắt đầu bằng 0):

 sum = foldr (+) 0

Hoặc đơn giản hơn: Thay vì g(x) = f(x), bạn chỉ có thể viết g = f.

Vì vậy, có: Nó liên quan chặt chẽ đến cà ri (hoặc các hoạt động như thành phần chức năng).


8
À, tôi hiểu rồi! Vì vậy, bạn xây dựng các hàm mới luôn chỉ bằng cách kết hợp các hàm khác chứ không phải khai báo các đối số ... Rất thanh lịch!
Paul Hollingsworth

22
Tôi thực sự không thích phải đặt tên mới cho các biến / đối số khi tôi đang lập trình. Đó là một lý do lớn khiến tôi yêu thích phong cách không điểm!
Martijn

2
Nó có liên quan gì đến Currying?
kaleidic

1
@kaleidic: Bởi vì không có tên biến, bạn cần phải soạn các hàm ứng dụng một phần. Đó là những gì chúng ta gọi là tách lạng bộ (hay chính xác hơn, những gì đang có thể thực hiện thông qua tách lạng bộ)
Dario

1
Ý bạn không phải là sum (x:xs) ...thay vì sum sum (x:xs) ...sao?
Ehtesh Choudhury

33

Kiểu không điểm có nghĩa là các đối số của hàm đang được định nghĩa không được đề cập rõ ràng, rằng hàm được xác định thông qua thành phần hàm.

Nếu bạn có hai chức năng, như

square :: a -> a
square x = x*x

inc :: a -> a
inc x = x+1

và nếu bạn muốn kết hợp hai hàm này thành một hàm để tính toán x*x+1, bạn có thể định nghĩa nó "toàn điểm" như sau:

f :: a -> a
f x = inc (square x)

Sự thay thế không có điểm sẽ không nói về lập luận x:

f :: a -> a
f = inc . square

21
Thật ngu ngốc, trong Haskell, cách 'không có điểm' thường là cách trông nhọn hơn (nhiều dấu chấm hơn). Sự khó chịu này làm cho một ghi nhớ tuyệt vời. (Cuốn sách Real World Haskell bình luận về điều này.)
Dan

3
Về @ bình luận của Dan, các Pointfree trang HaskellWiki cung cấp một lời giải thích lý do tại sao nó được gọi là pointfree .
Vincent Savard

2
@Dan: Tôi không nghĩ điều đó là ngu ngốc, vì điểm Haskell có nghĩa là "toán tử vòng tròn đó" (mặc dù trông giống như ° hơn). Nhưng thật khó hiểu, đặc biệt là khi bạn chưa quen với các ngôn ngữ lập trình hàm; mọi cuốn sách giới thiệu trên haskell nên giải thích theo phong cách không có điểm.
Sebastian Mach

12

Một mẫu JavaScript:

//not pointfree cause we receive args
var initials = function(name) {
  return name.split(' ').map(compose(toUpperCase, head)).join('. ');
};

const compose = (...fns) => (...args) => fns.reduceRight((res, fn) => [fn.call(null, ...res)], args)[0];
const join = m => m.join();

//pointfree
var initials = compose(join('. '), map(compose(toUpperCase, head)), split(' '));

initials("hunter stockton thompson");
// 'H. S. T'

Tài liệu tham khảo


5

Kiểu điểm tự do có nghĩa là mã không đề cập rõ ràng đến các đối số của nó, mặc dù chúng tồn tại và đang được sử dụng.

Điều này hoạt động trong Haskell vì cách các chức năng hoạt động.

Ví dụ:

myTake = take

trả về một hàm nhận một đối số, do đó không có lý do gì để nhập đối số một cách rõ ràng trừ khi bạn chỉ muốn.


1
Đôi khi, nó không hoạt động trong Haskell 98, như trong myShow = show. Có thêm về nó trên wiki Haskell
Ehtesh Choudhury

-1

Đây là một ví dụ trong TypeScript mà không có bất kỳ thư viện nào khác:

interface Transaction {
  amount: number;
}

class Test {
  public getPositiveNumbers(transactions: Transaction[]) {
    return transactions.filter(this.isPositive);

    //return transactions.filter((transaction: {amount: number} => transaction.amount > 0));
  }

  public getBigNumbers(transactions: Transaction[]) {
    // point-free
    return transactions.filter(this.moreThan(10));

    // not point-free
    // return transactions.filter((transaction: any) => transaction.amount > 10);
  }

  private isPositive(transaction: Transaction) {
    return transactions.amount > 0;
  }

  private moreThan(amount: number) {
    return (transaction: Transaction) => {
      return transactions.amount > amount;
    }
  }
}

Bạn có thể thấy point-free style "trôi chảy" hơn và dễ đọc hơn.


Đó không phải là kiểu không có điểm, đó chỉ là sự phân biệt giữa lambda và một hàm được đặt tên.
kralyk

@kralyk Tôi nghĩ rằng bạn đã bỏ lỡ điểm, this.moreThan(10)không phải là một hàm được đặt tên, đó là một hàm được đặt tên cũng như một hàm sẽ mặc nhiên (do đó, không có điểm) lấy a transactionlàm đầu vào.
AZ.
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.