Không phải lập trình chức năng chỉ là lập trình bắt buộc trá hình?


8

Một video trên YouTube Tôi đã xem giải thích sự khác biệt giữa bắt buộc và lập trình chức năng bằng cách chứng minh như thế nào những con số từ 1để 10được tóm tắt trong Java và trong Haskell tương ứng.

Trong Java, bạn phải nêu rõ từng bước và gán kết quả của từng bước cho một biến - đại loại như sau

int total = 0;
     for (int i = 1; i <= 10; i++){
         total = total + i;
     }
return total;

Trong Haskell, bạn có thể nói một cách đơn giản:

sum(1..10)

Câu hỏi của tôi là: Rõ ràng có một cái gì đó đang diễn ra trong nền tảng của ngôn ngữ Chức năng, và rằng một cái gì đó phải là một loại quy trình Bắt buộc. Có vẻ như Ngôn ngữ chức năng thực sự chỉ là một số API ngôn ngữ bắt buộc. Ví dụ, tôi có thể tạo một phần của ngôn ngữ chức năng bằng cách định nghĩa một phương thức sum(int start, int end)trong Java. Tôi đã thực sự tạo ra một loại ngôn ngữ mới ngay tại đó hay tôi chỉ định nghĩa một tập hợp các cuộc gọi phương thức mệnh lệnh ẩn các hướng dẫn bắt buộc từ bạn?

Tôi hy vọng nó rõ ràng những gì tôi đang đấu tranh để hiểu.


1
Đối với chính xác lý do bạn nêu, ví dụ về hàm sum không phải là một lý do tốt.
David Richerby

Đó là lý do tại sao nó được gọi là một phong cách , trái ngược với một loại máy tính mới.
dùng253751

Câu trả lời:


10

Nếu chúng ta bóc đường cú pháp ở mặt trước và tạo mã ở mặt sau và so sánh những gì xảy ra ở giữa khi chuyển đổi nguồn thành mã chạy cho các ngôn ngữ bắt buộc , chẳng hạn như C hoặc Java với các ngôn ngữ chức năng như ML hoặc OCaml, chúng ta thường sẽ tìm thấy Những khác biệt sau đây về cái gì, tại sao và như thế nào.

Mutable vs bất biến

Với lập trình chức năng, người ta có xu hướng sử dụng các giá trị bất biến, điều đó có nghĩa là chúng ta không phải lo lắng nếu giá trị thay đổi theo phương tiện bên ngoài chức năng hiện tại của chúng ta. Khi được sử dụng một cách chính xác, nó sẽ loại bỏ bất kỳ vấn đề nào liên quan đến tác dụng phụ .

Tập trung: Dữ liệu so với chức năng.

Khi người ta nghĩ về mã hóa bắt buộc, trước tiên người ta nghĩ đến cấu trúc dữ liệu và sau đó họ cần phương pháp nào, khi làm việc với lập trình chức năng, trước tiên người ta nghĩ đến những chức năng nào là cần thiết và sau đó tạo ra các loại dữ liệu cần thiết. Hầu hết các loại dữ liệu là danh sách lười biếng , (dòng suy nghĩ hoặc danh sách vô hạn) hoặc công đoàn bị phân biệt đối xử . Khi liên kết phân biệt được đệ quy, bạn ngay lập tức đã tạo một cây hoặc biểu đồ mà không phải viết tất cả mã đi bộ.

Generics / đa hình tham số

Điều này thật thú vị, và nếu tôi có sự thật chính xác của mình, đã được phát minh ra với lập trình chức năng và sau đó được ghép vào lập trình mệnh lệnh. Vì vậy, nếu bạn thích thuốc generic cảm ơn các nhà thiết kế ngôn ngữ chức năng.

Minh bạch tham chiếu / Song song

Bởi vì mã chức năng trong suốt tham chiếu có thể dễ dàng chuyển sang tính toán song song .

Chức năng / thành phần bậc cao

Vì các hàm có thể tạo các hàm mới và trả về các hàm, nên việc tạo các hàm mới dựa trên các hàm khác cũng dễ như tạo các biểu thức mới thay vì viết toàn bộ các phương thức mới. Điều này dẫn đến các hình thái rất hữu ích nếu vấn đề bạn đang giải quyết có thể được giải quyết bằng toán học. Thực hiện các phép biến đổi, nghĩ SQL và cập nhật, dễ dàng hơn nhiều với lập trình hàm. Như Wandering Logic lưu ý đây là nơi ngôn ngữ lập trình chức năng vượt trội.

Gõ: Tĩnh so với suy luận .

Do các kiểu được suy luận trái ngược với việc được lập trình viên thiết lập trong khi viết, nên có nhiều kiểm tra hơn để đảm bảo tính chính xác của mã và thường các hàm sẽ được đặt chung chung so với loại được đặt.

Kết hợp mẫu so với câu lệnh switch

Khi kết hợp kết hợp với các hiệp hội phân biệt đối xử, kết hợp của bạn được kiểm tra để đảm bảo bạn đã bao quát mọi kết quả. Đã bao nhiêu lần bạn gặp lỗi thời gian chạy vì bạn đã bỏ lỡ một trường hợp với câu lệnh chuyển đổi.


Trước tiên, khi làm việc với lập trình chức năng, người ta nghĩ đến những chức năng nào là cần thiết và sau đó làm cho các kiểu dữ liệu cần thiết là: phụ thuộc vào những gì người ta đang lập mô hình. Đặc biệt dữ liệu đệ quy rec loại là một điểm nóng trong FP cũng như các chức năng.
Hibou57

Khi kết hợp kết hợp với các hiệp hội bị phân biệt đối xử, kết quả khớp của bạn được kiểm tra để đảm bảo bạn đã bao quát mọi kết quả, trong khi (và như một ghi chú bên lề), các báo cáo trường hợp cũng được kiểm tra, với Ada, đây là điều bắt buộc. Bắt buộc không loại trừ việc khớp mẫu hoặc kiểm tra phạm vi bảo hiểm.
Hibou57

@ Hibou57 Bình luận tốt đẹp. Tôi sẽ quan tâm để xem câu trả lời của bạn.
Guy Coder

Tôi đồng ý rằng người ta có thể nghĩ về dữ liệu trước khi các chức năng được ghi nhận bởi Hibou57. Vì vậy, hãy để tôi làm rõ điều này một chút. Tôi có xu hướng sử dụng các ngôn ngữ chức năng cho những gì họ giỏi và sử dụng các ngôn ngữ bắt buộc cho những gì họ giỏi và sử dụng các ngôn ngữ logic cho những gì họ giỏi, v.v., và không gặp vấn đề gì khi sử dụng hai ngôn ngữ trở lên cho một vấn đề, phân tách nhiệm vụ giữa các ngôn ngữ. Vì vậy, khi tôi sử dụng ngôn ngữ chức năng, tôi có xu hướng nghĩ về chức năng trước và khi tôi cần dữ liệu liên tục, tôi có xu hướng nghĩ dữ liệu trước và logic tôi sử dụng ngôn ngữ logic, v.v.
Guy Coder

1
Đối với tuyên bố trường hợp Ada, ở đây tham chiếu: 5.4 Báo cáo trường hợp (cho lần sửa đổi cuối cùng cho đến ngày này). Đặc biệt về vấn đề đó, hãy lưu ý cách diễn đạt về phạm vi bảo hiểm của Cameron
Hibou57

9

Một ngôn ngữ lập trình chức năng là đáng chú ý cho những gì nó cấm . Nó cấm sửa đổi một biến hoặc cấu trúc dữ liệu hiện có. Bạn có thể lập trình theo "kiểu chức năng" trong một số ngôn ngữ lập trình bắt buộc, nhưng ngôn ngữ sẽ không bảo vệ bạn khỏi việc vô tình sửa đổi một biến hoặc cấu trúc dữ liệu hiện có. Ví dụ, đây là một phiên bản đệ quy, có chức năng, sumtrong Java:

int sum(int start, int end) {
  if (start > end) return 0;
  else {
    int total = start + sum(start+1, end);
    return total;
  }
}

Trong đó các ngôn ngữ lập trình chức năng vượt trội là tất cả chúng đều có chức năng "hạng nhất". Đó là: một hàm có thể được sử dụng làm giá trị, giống như một số nguyên hoặc cấu trúc dữ liệu. Một số ngôn ngữ bắt buộc cũng có các hàm hạng nhất (đáng chú ý là C và C ++), nhưng trong Java, bạn phải giả mạo nó với một đối tượng bằng một phương thức duy nhất (thường được gọi apply()hoặc một cái gì đó.) Các hàm hạng nhất cho phép chúng ta khái quát sumhàm này thành một chức năng làm giảm bất kỳ toán tử:

interface IntegerOperator {
  int apply(int a, int b);
}

int sum(IntegerOperator op, int start, int end) {
  if (start > end) return 0;
  else {
    int total = op.apply(start, sum(op, start+1, end))
    return total;
  }
}

class AdditionOperator implements IntegerOperator {
  int apply(int a, int b) { return a+b; }
}

int total = sum(new AdditionOperator(), 1, 10);

Nếu tôi đang viết bằng ngôn ngữ lập trình chức năng, tôi sẽ biết rằng mọi hàm thực sự là một hàm (nó trả về cùng một giá trị mỗi khi nó được gọi với cùng tham số), vì vậy tôi sẽ biết rằng trong:

int total1 = sum(new ReallyStrangeOperator(), 1, 10);
int total2 = sum(new ReallyStrangeOperator(), 1, 10);

total1total2có cùng giá trị (ví dụ: tôi có thể tối ưu hóa cuộc gọi thứ hai đến sum), trong khi đó, trong ngôn ngữ lập trình bắt buộc, tôi không biết liệu có ReallyStrangeOperator(1,2)trả về cùng một giá trị mỗi lần hay không.


2
Cảm ơn câu trả lời thực sự nhiều thông tin. Tôi đã chấp nhận người khác nhưng tôi có thể dễ dàng chấp nhận bạn và viết nhận xét này trong người khác.
CodyBugstein
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.