Điều gì đã kích hoạt sự phổ biến của các chức năng lambda trong các ngôn ngữ lập trình chính hiện đại?


112

Trong vài năm qua, các chức năng ẩn danh (chức năng lambda của AKA) đã trở thành một cấu trúc ngôn ngữ rất phổ biến và hầu hết mọi ngôn ngữ lập trình chính / chính đã giới thiệu chúng hoặc được lên kế hoạch để giới thiệu chúng trong phiên bản sắp tới của tiêu chuẩn.

Tuy nhiên, các hàm ẩn danh là một khái niệm rất lâu đời và rất nổi tiếng trong Toán học và Khoa học máy tính (được phát minh bởi nhà toán học Alonzo Church vào khoảng năm 1936, và được sử dụng bởi ngôn ngữ lập trình Lisp từ năm 1958, xem ví dụ ở đây ).

Vậy tại sao các ngôn ngữ lập trình chính thống ngày nay (nhiều ngôn ngữ bắt nguồn từ 15 đến 20 năm trước) hỗ trợ các chức năng lambda ngay từ đầu và chỉ giới thiệu chúng sau này?

Và điều gì đã kích hoạt việc áp dụng lớn các chức năng ẩn danh trong vài năm qua? Có một số sự kiện cụ thể, yêu cầu mới hoặc kỹ thuật lập trình đã bắt đầu hiện tượng này?

LƯU Ý QUAN TRỌNG

Trọng tâm của câu hỏi này là giới thiệu các chức năng ẩn danh trong các ngôn ngữ chính, hiện đại (và do đó, có thể với một vài ngoại lệ, không có chức năng). Ngoài ra, lưu ý rằng các hàm ẩn danh (khối) có trong Smalltalk, không phải là ngôn ngữ chức năng và các hàm có tên bình thường đã có mặt ngay cả trong các ngôn ngữ thủ tục như C và Pascal trong một thời gian dài.

Xin đừng nói quá nhiều câu trả lời của bạn bằng cách nói về "việc áp dụng mô hình chức năng và lợi ích của nó", bởi vì đây không phải là chủ đề của câu hỏi.


7
15-20 năm trước mọi người đã hỏi cùng một câu hỏi về OO ... đó không phải là một khái niệm mới nhưng nó đã có sự bùng nổ về mức độ phổ biến.
MattDavey

7
@MattDavey Hầu hết chắc chắn sẽ không đồng ý, nhưng sau đó tôi phải nhắc nhở họ rằng "hầu hết các nhà phát triển Smalltalk" không thực sự là nhiều người; P
yannis

30
Tôi nghĩ rằng câu hỏi thú vị hơn là những gì đã kích hoạt sự sụp đổ của họ ! Rốt cuộc, có một thời gian, khi hầu hết các ngôn ngữ hiện đại đã có lambdas, thì các ngôn ngữ như Java và C ++ đã trở nên phổ biến. (Mặc dù tôi không chính xác gọi Java là ngôn ngữ "hiện đại". Khái niệm hiện đại nhất trong Java là Generics, xuất hiện từ cuối thập niên 60 / đầu thập niên 70. Ngay cả sự kết hợp các tính năng Java cung cấp, an toàn con trỏ, an toàn bộ nhớ, loại an toàn, GC, gõ tĩnh OO, Generics đều tồn tại ở Eiffel vào năm 1985 và tốt hơn nhiều, IMHO.)
Jörg W Mittag

31
Ngay cả trước khi Java 1.0 xuất hiện, trong khi nó vẫn đang trong giai đoạn thiết kế ban đầu, khá nhiều người đã chỉ ra rằng Java cần lambdas. Một số nhà thiết kế đã làm việc trên Java bao gồm Guy Steele (người đề xuất Lisp, đồng thiết kế của Scheme, đồng tác giả của Common Lisp, nhà thiết kế của Fortress), James Gosling (đã viết trình thông dịch Emacs Lisp đầu tiên cho PC), Gilad Bracha (Smalltalk người đề xướng, đồng thiết kế của Animorphic Smalltalk, nhà thiết kế của Drameak), Phil Wadler (đồng thiết kế của Haskell), Martin Oderky (nhà thiết kế của Scala). Làm thế nào Java kết thúc mà không có lambdas thực sự vượt quá tôi.
Jörg W Mittag

8
"Một chút xíu" thường có nghĩa là chức năng 50%, tiếng ồn 50%.
kevin cline

Câu trả lời:


86

Chắc chắn có một xu hướng đáng chú ý đối với lập trình chức năng, hoặc ít nhất là một số khía cạnh nhất định của nó. Một số ngôn ngữ phổ biến tại một số thời điểm đã áp dụng các hàm ẩn danh là C ++ ( C ++ 11 ), PHP ( PHP 5.3.0 ), C # ( C # v2.0 ), Delphi (kể từ 2009), Objective C ( khối ) trong khi Java 8 sẽ mang lại sự hỗ trợ cho lambdas cho ngôn ngữ . Và có những ngôn ngữ phổ biến thường không được coi là chức năng nhưng được hỗ trợ các chức năng ẩn danh ngay từ đầu hoặc ít nhất là sớm, ví dụ sáng chói là JavaScript.

Như với tất cả các xu hướng, cố gắng tìm kiếm một sự kiện duy nhất gây ra chúng có lẽ là một sự lãng phí thời gian, nó thường là sự kết hợp của các yếu tố, hầu hết trong số đó không thể định lượng được. Thực tế Common Lisp , xuất bản năm 2005, có thể đã đóng một vai trò quan trọng trong việc thu hút sự chú ý mới đối với Lisp như một ngôn ngữ thực tế , vì trong một thời gian, Lisp chủ yếu là ngôn ngữ bạn gặp trong môi trường học thuật, hoặc thị trường thích hợp rất cụ thể. Sự phổ biến của JavaScript cũng có thể đóng một vai trò quan trọng trong việc mang lại sự chú ý mới cho các chức năng ẩn danh, như giải thích tuyệt vời trong câu trả lời của ông .

Khác với việc áp dụng các khái niệm chức năng từ các ngôn ngữ đa mục đích, cũng có một sự thay đổi đáng chú ý đối với các ngôn ngữ chức năng (hoặc chủ yếu là chức năng). Các ngôn ngữ như Erlang (1986), Haskell (1990), OCaml (1996), Scala (2003), F # (2005), Clojure (2007) và thậm chí các ngôn ngữ cụ thể trong miền như R (1993) dường như đã đạt được sự tăng trưởng mạnh mẽ sau khi họ được giới thiệu Xu hướng chung đã mang lại sự chú ý mới cho các ngôn ngữ chức năng cũ hơn, như Scheme (1975), và rõ ràng là Lisp chung.

Tôi nghĩ rằng sự kiện quan trọng hơn là việc áp dụng lập trình chức năng trong ngành. Tôi hoàn toàn không biết tại sao điều đó lại không xảy ra, nhưng dường như vào một lúc nào đó, trong những năm đầu và giữa thập niên 90, chương trình chức năng bắt đầu tìm thấy vị trí của nó trong ngành, bắt đầu (có lẽ) với sự phát triển của Erlang ứng dụng viễn thôngHaskell trong thiết kế hàng không vũ trụ và phần cứng .

Joel Spolsky đã viết một bài đăng trên blog rất thú vị, The Perils of JavaSchools , nơi ông lập luận chống lại xu hướng (lúc đó) của các trường đại học để ủng hộ Java hơn các ngôn ngữ khác, có lẽ khó học hơn. Mặc dù bài đăng trên blog ít liên quan đến lập trình chức năng, nhưng nó xác định một vấn đề chính:

Trong đó nằm trong cuộc tranh luận. Nhiều năm than vãn bởi những sinh viên CS lười biếng như tôi, kết hợp với những lời phàn nàn từ ngành công nghiệp về việc có bao nhiêu chuyên ngành CS tốt nghiệp từ các trường đại học Mỹ, đã phải trả giá, và trong thập kỷ qua, một số lượng lớn các trường hoàn toàn tốt đã đi 100% Java. Đó là hông, các nhà tuyển dụng sử dụng "grep" để đánh giá sơ yếu lý lịch có vẻ thích nó, và, tốt nhất, không có gì đủ khó để Java thực sự loại bỏ các lập trình viên mà không có phần não bộ chỉ ra hoặc đệ quy, vì vậy tỷ lệ bỏ học thấp hơn và các khoa khoa học máy tính có nhiều sinh viên hơn và ngân sách lớn hơn, và tất cả đều ổn.

Tôi vẫn nhớ tôi đã ghét Lisp đến mức nào, khi lần đầu tiên tôi gặp cô ấy trong những năm học đại học. Đó chắc chắn là một tình nhân khắc nghiệt, và đó không phải là ngôn ngữ mà bạn có thể làm việc ngay lập tức (ít nhất là tôi không thể). So với Lisp, Haskell (chẳng hạn) thân thiện hơn rất nhiều, bạn có thể làm việc hiệu quả mà không cần nhiều nỗ lực và không cảm thấy mình là một thằng ngốc hoàn toàn, và đó cũng có thể là một yếu tố quan trọng trong việc chuyển sang lập trình chức năng.

Tất cả trong tất cả, đây là một điều tốt. Một số ngôn ngữ đa mục đích đang áp dụng các khái niệm về mô hình có thể có vẻ phức tạp đối với hầu hết người dùng của họ trước đây và khoảng cách giữa các mô hình chính đang thu hẹp.

Câu hỏi liên quan:

Đọc thêm:


Cảm ơn câu trả lời (và rất nhiều ý tưởng thú vị). +1 Tuy nhiên, tôi sẽ lập luận rằng việc đưa (chỉ) lambdas vào ngôn ngữ lập trình là một bước rất nhỏ đối với FP, và nó thậm chí có thể gây nhầm lẫn cho nhiều người (lambdas đang làm gì một mình trong ngôn ngữ mệnh lệnh?). Sau khi học một số Haskell, Scala và SML, tôi không có cảm giác mình có thể thực hiện FP thực sự với một ngôn ngữ bắt buộc chỉ hỗ trợ lambdas (còn về cà ri, và khớp mẫu, không thay đổi?).
Giorgio


2
@YannisRizos: Perl's có chức năng ẩn danh kể từ lần phát hành đầu tiên vào ngày 5 (1994), nhưng chúng không hoàn toàn "đúng" cho đến 5,004 (1997).
Blrfl

1
@penartur Đó là những gì tôi nghĩ quá, nhưng một trình soạn thảo thân thiện khắc phục tôi bằng cách chỉ cho tôi ở đây: msdn.microsoft.com/en-us/library/0yw3tz5k%28v=vs.80%29.aspx
Yannis

Tôi nghĩ rằng có lẽ "sự kiện" chính mang lại sự phổ biến của các ngôn ngữ chức năng là web. Cụ thể hơn, sự thay đổi từ các chương trình máy tính để bàn sang phía máy chủ. Điều này cho phép nhà phát triển tự do lựa chọn bất kỳ ngôn ngữ lập trình. Paul Graham và Lisp trong những năm 90 là một ví dụ đáng chú ý.
Gilad Naor

32

Tôi nghĩ thật thú vị khi mức độ phổ biến của lập trình chức năng đã song hành với sự phát triển và phổ biến của Javascript. Javascript có rất nhiều tính năng cơ bản dọc theo phổ lập trình chức năng mà tại thời điểm tạo ra nó (1995) không phổ biến lắm trong các ngôn ngữ lập trình chính thống (C ++ / Java). Nó đột nhiên được đưa vào dòng chính là ngôn ngữ lập trình web phía khách hàng duy nhất. Đột nhiên, rất nhiều lập trình viên chỉ cần biết Javascript và do đó bạn phải biết một số tính năng của ngôn ngữ lập trình chức năng.

Tôi tự hỏi các ngôn ngữ / tính năng chức năng phổ biến sẽ như thế nào nếu không có sự tăng trưởng đột ngột của Javascript.


5
Javascript chắc chắn là một ngôn ngữ quan trọng, nhưng tôi không chắc việc giới thiệu Javascript có thể giải thích cho sự phổ biến của lập trình chức năng hay không: rất nhiều ngôn ngữ lập trình chức năng khác đã xuất hiện trong những năm qua, như Yannis đã minh họa trong câu trả lời của mình .
Giorgio

8
@Giorgio - có thể có rất nhiều ngôn ngữ lập trình chức năng khác, nhưng (tương đối) không ai sử dụng chúng. Việc sử dụng JS và quan điểm gia tăng rằng cách tạo ra functor của C ++ / Java là đau đớn và khó chịu thực sự là động lực cho dòng chính, ngay cả khi các ngôn ngữ hàn lâm hơn đã cải thiện cách chúng nên được thực hiện.
Telastyn

1
Sự phổ biến của các ngôn ngữ động nói chung được ám chỉ như là một lời giải thích cho sự phổ biến của Haskell: book.realworldhaskell.org/read/...
Yannis

Ngoài ra, trọng tâm của câu hỏi không phải là sự phổ biến của FP nói chung, mà là về việc giới thiệu muộn các chức năng ẩn danh trong các ngôn ngữ đa mục đích, phi chức năng. Ngay cả khi công chúng lớn (hầu hết các lập trình viên) không biết họ, các nhà thiết kế ngôn ngữ cũng biết họ rất rõ. Phải có một lý do để bỏ chúng ngay từ đầu. Có lẽ chúng được coi là không trực quan cho các nhà phát triển của 90 mối quan hệ đầu tiên.
Giorgio

@giorgio - Chúng thực hiện rắc rối hơn nhiều so với các hàm xử lý kiểu Java. Kết hợp với việc thiếu kiến ​​thức / áp dụng và đó là một lựa chọn thiết kế khá rõ ràng.
Telastyn

27

Trình xử lý sự kiện JavaScript và DOM có nghĩa là hàng triệu lập trình viên phải tìm hiểu ít nhất một chút về các chức năng của lớp đầu tiên để thực hiện bất kỳ tương tác nào trên web.

Từ đó, đây là một bước tương đối ngắn để các chức năng ẩn danh . Vì JavaScript không kết thúc this, nó cũng khuyến khích bạn tìm hiểu về các lần đóng. Và sau đó, bạn thật tuyệt vời: bạn hiểu các hàm hạng nhất ẩn danh gần với các phạm vi từ vựng.

Một khi bạn cảm thấy thoải mái với nó, bạn muốn nó ở mọi ngôn ngữ bạn sử dụng.


7
+1 nó không chỉ là về các chức năng ẩn danh. Đóng cửa là một khái niệm rộng hơn nhiều so với việc chỉ xác định một hàm nội tuyến tạm thời.
phkahler

@phkahler: Bạn đã đúng và, theo nghĩa này, Java đã có các bao đóng (và thậm chí còn mạnh hơn những gì bạn nhận được với một hàm theo nghĩa đen) nhưng nó thiếu một ký hiệu ngắn gọn cho trường hợp phổ biến của lớp ẩn danh một phương thức.
Giorgio

17

Nó chắc chắn không phải là yếu tố duy nhất , nhưng tôi sẽ chỉ ra sự phổ biến của Ruby. Không nói điều này quan trọng hơn bất kỳ câu trả lời nào trong số sáu câu trả lời đã có trên bảng, nhưng tôi nghĩ rằng nhiều điều đã xảy ra cùng một lúc và nó hữu ích để liệt kê tất cả.

Ruby không phải là một ngôn ngữ chức năng và lambdas, prods và khối của nó có vẻ lộn xộn khi bạn đã sử dụng một cái gì đó như ML, nhưng thực tế là, nó đã phổ biến khái niệm ánh xạ và giảm bớt cho một thế hệ lập trình viên trẻ chạy trốn Java và PHP Đồng cỏ. Lambdas trong một số ngôn ngữ dường như là động thái phòng thủ hơn bất kỳ thứ gì khác ("Dính xung quanh! Chúng tôi cũng có những thứ đó !!)

Nhưng cú pháp khối và cách nó được tích hợp với .each, .map, .reduce và vv đã phổ biến ý tưởng về một hàm ẩn danh ngay cả khi nó thực sự là một cấu trúc cú pháp hoạt động giống như một coroutine. Và việc chuyển đổi dễ dàng sang một Proc thông qua & biến nó thành một loại thuốc cổng cho lập trình chức năng.

Tôi lập luận rằng các lập trình viên Ruby on Rails viết JavaScript đã được bật để làm mọi thứ theo kiểu chức năng nhẹ. Kết hợp với viết blog lập trình viên, phát minh ra Reddit, hacker News và Stack Overflow cùng một lúc và các ý tưởng lan truyền nhanh hơn trên Internet so với thời của Newsgroups.

TL; DR: Ruby, Rails, JavaScript, viết blog và Reddit / Hacker News / Stack Overflow đã đẩy các ý tưởng chức năng đến một thị trường đại chúng, vì vậy mọi người đều muốn chúng trong các ngôn ngữ hiện có để ngăn chặn sự đào tẩu thêm.


2
+1 Để có câu trả lời hay và (nếu tôi có thể, vì tôi chỉ có một upvote) +1 để chỉ ra rằng "Lambdas trong một số ngôn ngữ dường như là động thái phòng thủ hơn bất kỳ thứ gì khác (" Hãy bám lấy! Chúng tôi cũng có những thứ đó !!) ". Tôi nghĩ đây cũng là một yếu tố. Đối với một số ngôn ngữ, lambdas là một tính năng dễ có, mặc dù nó có rất ít sức mạnh biểu cảm cho toàn bộ ngôn ngữ, nó mang lại cho ngôn ngữ một sự phổ biến (a số lượng lập trình viên dường như nghĩ rằng hỗ trợ cho các chức năng ẩn danh tương đương với hỗ trợ lập trình chức năng đầy đủ).
Giorgio

2
Tôi thực sự nghĩ rằng đây là lý do tại sao hầu hết các ngôn ngữ đã thực hiện cú pháp khối trong những năm gần đây. Nhưng cách duy nhất để đảm bảo là hỏi anh ấy các nhà phát triển ngôn ngữ về động cơ của họ. Chúng tôi chỉ có thể suy đoán imo.
SpoBo

Đối với tôi, Ruby là ngôn ngữ đầu tiên tạo ra khối rock và rất hấp dẫn, vì vậy +1. Haskell có thể đã có một hiệu ứng là tốt.
rogerdpack

13

Như Yannis đã chỉ ra, có một số yếu tố đã ảnh hưởng đến việc áp dụng các hàm bậc cao trong các ngôn ngữ mà trước đây không có. Một trong những mục quan trọng mà anh ta chỉ chạm nhẹ là sự phổ biến của bộ xử lý đa lõi và cùng với đó là mong muốn xử lý song song và đồng thời hơn.

Kiểu bản đồ / bộ lọc / rút gọn của lập trình chức năng rất thân thiện với việc song song hóa, cho phép lập trình viên dễ dàng sử dụng nhiều lõi, mà không cần viết bất kỳ mã luồng rõ ràng nào.

Như Giorgio lưu ý, có nhiều thứ để lập trình chức năng hơn là chỉ các hàm bậc cao. Các hàm, cộng với một bản đồ / bộ lọc / giảm mẫu lập trình tính bất biến là cốt lõi của lập trình hàm. Những điều này làm cho các công cụ mạnh mẽ của lập trình song song và đồng thời. Rất may, nhiều ngôn ngữ đã hỗ trợ một số khái niệm về tính bất biến và thậm chí nếu không, các lập trình viên có thể coi mọi thứ là bất biến cho phép các thư viện và trình biên dịch tạo và quản lý các hoạt động không đồng bộ hoặc song song.

Thêm các hàm bậc cao vào một ngôn ngữ là một bước quan trọng để đơn giản hóa việc lập trình đồng thời.

Cập nhật

Tôi sẽ thêm một vài ví dụ chi tiết hơn để giải quyết những lo ngại mà Loki đã lưu ý.

Hãy xem xét mã C # sau đây đi qua bộ sưu tập các vật dụng, tạo ra một danh sách mới về giá vật dụng.

List<float> widgetPrices;
    float salesTax = RetrieveLocalSalesTax();
foreach( Widget w in widgets ) {
    widgetPrices.Add( CalculateWidgetPrice( w, salesTax ) );
}

Đối với một bộ sưu tập lớn các widget hoặc phương thức CompateWidgetprice (Widget) tính toán chuyên sâu, vòng lặp này sẽ không sử dụng tốt bất kỳ lõi có sẵn nào. Để thực hiện các tính toán giá trên các lõi khác nhau sẽ yêu cầu lập trình viên tạo và quản lý rõ ràng các luồng, chuyển công việc xung quanh và thu thập kết quả cùng nhau.

Hãy xem xét một giải pháp khi các hàm bậc cao đã được thêm vào C #:

var widgetPrices = widgets.Select( w=> CalculateWidgetPrice( w, salesTax ) );

Vòng lặp foreach đã được chuyển vào phương thức Chọn, ẩn chi tiết triển khai của nó. Tất cả những gì còn lại cho lập trình viên là nói với Chọn chức năng nào sẽ áp dụng cho từng phần tử. Điều này sẽ cho phép triển khai Chọn để chạy các phép tính theo parellel, xử lý tất cả các mối quan tâm đồng bộ hóa và quản lý luồng mà không cần sự tham gia của lập trình viên.

Nhưng, tất nhiên, Chọn không hoạt động song song. Đó là nơi mà tính bất biến xuất hiện. Việc triển khai Chọn không biết rằng hàm được cung cấp (Tính toán trên đây) không có tác dụng phụ. Hàm này có thể thay đổi trạng thái của chương trình bên ngoài giao diện Chọn và đồng bộ hóa, phá vỡ mọi thứ. Ví dụ: trong trường hợp này, giá trị của salesTax có thể bị thay đổi do lỗi. Các ngôn ngữ chức năng thuần túy cung cấp tính bất biến, do đó, chức năng Chọn (bản đồ) có thể biết chắc chắn rằng không có trạng thái nào thay đổi.

C # giải quyết vấn đề này bằng cách cung cấp PLINQ thay thế cho Linq. Điều đó sẽ trông giống như:

var widgetPrices = widgets.AsParallel().Select(w => CalculateWidgetPrice( w, salesTax) );

Việc này sử dụng đầy đủ tất cả các lõi của hệ thống của bạn mà không cần quản lý rõ ràng các lõi đó.


Tôi chỉ ra mong muốn xử lý song song và đồng thời hơn, nó đã được thảo luận trong bài viết ACM "Lịch sử của Erlang" mà tôi đang liên kết đến trong đoạn thứ tư. Nhưng đó là một điểm rất tốt, và tôi có lẽ nên mở rộng thêm một chút nữa. +1 vì bây giờ tôi không phải; P
yannis

Bạn nói đúng, tôi không nhìn kỹ đủ. Tôi chỉnh sửa nhận xét của tôi.
Ben

Ồ, bạn không thực sự phải làm điều đó, tôi đã không phàn nàn;)
yannis

4
Không có gì bạn mô tả ở trên đòi hỏi lambdas. Các chức năng tương tự đạt được dễ dàng như với các chức năng được đặt tên. Ở đây bạn chỉ đơn giản là tài liệu a causevà a perceived affectmà không giải thích correlation. Dòng cuối cùng IMO là những gì câu hỏi về; nhưng bạn đã không trả lời nó. Tại sao nó đơn giản hóa chương trình đồng thời.
Martin York

@Ben: Hãy cẩn thận rằng ví dụ của bạn liên quan đến các hàm bậc cao hơn không cần sử dụng các hàm ẩn danh. Câu trả lời của bạn chứa những ý tưởng thú vị (cho một câu hỏi khác) nhưng sẽ lạc đề ngay bây giờ.
Giorgio

9

Tôi đồng ý với nhiều câu trả lời ở đây, nhưng điều thú vị là khi tôi biết về lambdas và nhảy lên chúng, đó không phải là bất kỳ lý do nào mà người khác đã đề cập.

Trong nhiều trường hợp, các hàm lambda chỉ đơn giản là cải thiện khả năng đọc mã của bạn. Trước lambdas khi bạn gọi một phương thức chấp nhận một con trỏ hàm (hoặc hàm hoặc ủy nhiệm), bạn phải xác định phần thân của hàm đó ở một nơi khác, vì vậy khi bạn có cấu trúc "foreach", trình đọc của bạn sẽ phải chuyển sang một hàm khác một phần của mã để xem chính xác những gì bạn đã dự định làm với từng yếu tố.

Nếu phần thân của hàm xử lý các phần tử chỉ có vài dòng, tôi sẽ sử dụng một hàm ẩn danh vì bây giờ khi bạn đang đọc mã, chức năng vẫn không thay đổi, nhưng trình đọc không phải nhảy qua lại, toàn bộ việc thực hiện là ngay trước mặt anh.

Nhiều kỹ thuật lập trình chức năng và song song hóa có thể đạt được mà không có chức năng ẩn danh; chỉ cần khai báo một thông thường và chuyển một tham chiếu đến đó bất cứ khi nào bạn cần. Nhưng với lambdas dễ dàng viết mã và dễ đọc mã được cải thiện rất nhiều.


1
Giải thích rất tốt (+1). Các lập trình viên Lisp đã nhận thức được tất cả những điều này kể từ năm 1958. ;-)
Giorgio

4
@Giorgio: Chắc chắn, nhưng các lập trình viên lisp cũng phải mua bàn phím đặc biệt với các phím ngoặc mở / đóng được củng cố :)
DXM

@DXM: không phải bàn phím, họ có thêm thiết bị đầu vào giống như bàn đạp piano để mở và đóng dấu ngoặc đơn ;-)
vartec

@DXM, vartec: Gần đây bạn đã thực hiện một số Đề án và tôi thấy dấu ngoặc đơn OK. Một số mã C ++ có thể khó hiểu hơn nhiều (và tôi có nhiều kinh nghiệm hơn với C ++ so với Scheme). :-)
Giorgio

9

Đã tham gia vào lịch sử gần đây ở đây một chút, tôi tin rằng một yếu tố là việc bổ sung các khái quát cho Java và .NET. Điều đó tự nhiên dẫn đến Func < , > và các khái niệm trừu tượng được đánh máy mạnh mẽ khác (Nhiệm vụ < >, Async < >, v.v.)

Trong thế giới .NET, chúng tôi đã thêm các tính năng này một cách chính xác để hỗ trợ FP. Điều đó đã kích hoạt một tập hợp các công việc ngôn ngữ liên quan đến lập trình chức năng, đặc biệt là C # 3.0, LINQ, Rx và F #. Sự tiến bộ đó cũng ảnh hưởng đến các hệ sinh thái khác và vẫn tiếp tục cho đến ngày nay trong C #, F # và TypeScript.

Dĩ nhiên, nó cũng giúp Haskell làm việc tại MSR :)

Tất nhiên cũng có nhiều ảnh hưởng khác (chắc chắn là JS) và các bước này lần lượt bị ảnh hưởng bởi nhiều thứ khác - nhưng việc thêm thuốc generic vào các ngôn ngữ này đã giúp phá vỡ chính thống OO cứng nhắc của những năm cuối thập niên 90 trong phần lớn của thế giới phần mềm và giúp mở ra cánh cửa cho FP.

Don Syme

ps F # là 2003, không phải năm 2005 - mặc dù chúng tôi sẽ nói rằng nó không đạt 1.0 cho đến năm 2005. Chúng tôi cũng đã thực hiện một nguyên mẫu Haskell.NET vào năm 2001-22.


Chào mừng bạn Tôi đã sử dụng 2005 cho F #, vì đó là năm được báo cáo trong bài viết Wikipedia của F # là năm phát hành ổn định đầu tiên. Bạn có muốn tôi thay đổi nó thành 2003?
yannis

4

Đây không phải là một câu trả lời nghiêm túc, nhưng câu hỏi khiến tôi nhớ đến một bài viết hài hước thú vị của James Iry - Một bản tóm tắt, không đầy đủ và chủ yếu là Lịch sử sai về ngôn ngữ lập trình bao gồm cụm từ sau:

"Lambdas bị xuống hạng đến mức tối nghĩa tương đối cho đến khi Java làm cho chúng trở nên phổ biến bằng cách không có chúng."


cụm từ vàng :)
pistache

4

Từ những gì tôi thấy hầu hết các câu trả lời tập trung vào việc giải thích lý do tại sao nói chung, lập trình chức năng đã làm cho nó trở lại và biến nó thành xu hướng chính. Tôi cảm thấy điều này tuy nhiên không thực sự trả lời câu hỏi về các chức năng ẩn danh nói riêng và tại sao chúng đột nhiên trở nên phổ biến.

Những gì đã thực sự đạt được sự phổ biến, là đóng cửa . Vì trong hầu hết các trường hợp, các hàm đóng là các hàm vứt đi được chuyển qua, rõ ràng nên sử dụng cú pháp hàm ẩn danh cho các hàm này. Và trên thực tế, trong một số ngôn ngữ, đó là cách duy nhất để tạo sự đóng cửa.

Tại sao đóng cửa đã trở nên phổ biến? Bởi vì chúng rất hữu ích trong lập trình hướng sự kiện, khi tạo các hàm gọi lại . Hiện tại đây là cách viết mã máy khách JavaScript (thực tế đó là cách viết bất kỳ mã GUI nào). Hiện tại, đây cũng là cách viết mã back-end hiệu quả cao cũng như mã hệ thống, vì mã được viết trong mô hình hướng sự kiện thường không đồng bộ và không chặn . Đối với back-end, điều này trở nên phổ biến như là giải pháp cho vấn đề C10K .


Cảm ơn vì đã nhấn mạnh rằng câu hỏi này không phải là về lập trình chức năng (+1) bởi vì (1) ý tưởng về một khối mã được truyền qua như một đối số cũng được sử dụng trong các ngôn ngữ phi chức năng như Smalltalk và (2) trạng thái biến đổi được chụp từ bối cảnh từ vựng của một bao đóng (có thể trong nhiều triển khai lambda) chắc chắn là không có chức năng . Và vâng, có đóng cửa, bước để đóng cửa ẩn danh là ngắn. Điều thú vị là việc đóng cửa cũng đã được biết đến từ lâu và lập trình hướng sự kiện đã được sử dụng (theo như tôi biết) từ những năm tám mươi.
Giorgio

Nhưng có lẽ chỉ trong vài năm gần đây, mọi thứ trở nên rõ ràng rằng việc đóng cửa có thể được sử dụng thường xuyên hơn nhiều so với suy nghĩ trước đây.
Giorgio

@Giorgio: vâng, hầu hết các khái niệm hiện đang được sử dụng đã tồn tại rất lâu. Tuy nhiên, chúng chưa được sử dụng theo cách này, chúng được sử dụng ngay bây giờ.
vartec

1

Tôi nghĩ lý do là sự phổ biến ngày càng tăng của lập trình đồng thời và phân tán, trong đó cốt lõi của lập trình hướng đối tượng (đóng gói trạng thái thay đổi với các đối tượng) không còn được áp dụng. Trong trường hợp của một hệ thống phân phối, bởi vì có không một quốc gia chia sẻ (trừu tượng và phần mềm của khái niệm đó là bị rò rỉ) và trong trường hợp của một hệ thống đồng thời, vì đồng bộ hóa đúng cách tiếp cận với nhà nước chia sẻ đã được chứng minh cồng kềnh và dễ bị lỗi. Đó là, một trong những lợi ích chính của lập trình hướng đối tượng không còn áp dụng cho nhiều chương trình, làm cho mô hình hướng đối tượng ít hữu ích hơn nhiều so với trước đây.

Ngược lại, mô hình chức năng không sử dụng trạng thái đột biến. Do đó, bất kỳ kinh nghiệm nào chúng tôi có được với các mô hình và mô hình chức năng đều có thể chuyển đổi ngay lập tức sang tính toán đồng thời và phân tán. Và thay vì phát minh lại bánh xe, ngành công nghiệp hiện mượn các mô hình và tính năng ngôn ngữ đó để giải quyết nhu cầu của nó.


4
Các hàm ẩn danh trong một số ngôn ngữ dòng chính (ví dụ C ++ 11) cho phép trạng thái có thể thay đổi (thậm chí chúng có thể nắm bắt các biến từ môi trường xác định và thay đổi chúng trong khi thực hiện). Vì vậy, tôi nghĩ rằng việc nói về mô hình chức năng nói chung và về tính bất biến nói riêng là một chút ngoài phạm vi của câu hỏi đang được hỏi.
Giorgio

Chỉ cần đọc một số ghi chú tính năng cho Java 8, một trong những mục tiêu chính của lambda dự án là hỗ trợ đồng thời. Và điều đó ngay lập tức đưa chúng ta đến cụm sao khả năng biến đổi mà tất cả các javabeans tuyệt vời này sẽ chạy vào. Khi Java có lambdas (giả sử nó thực sự có trong phiên bản cuối cùng của phiên bản 8), thì họ cần phải giải quyết vấn đề mặc định không thay đổi, bằng cách nào đó (nó phá hủy ngôn ngữ, suy nghĩ trong Lisp - các hàm miễn phí hiệu ứng phụ - thay vào đó trong COBOL - whack trên DATA DIVISION / COPYBOOK)
Roboprog

Nói hay lắm. Việc di chuyển khỏi trạng thái có thể thay đổi làm cho việc đồng thời trở nên dễ dàng hơn và các công nghệ như cascalog và spark dễ dàng phân phối lập trình chức năng trên một cụm máy tính. Xem glennengstrand.info/analytics/distribution/feftal/ khuyên để biết thêm chi tiết về cách thức và lý do.
Glenn

1

Nếu có thể thêm 0,02 € của tôi, mặc dù tôi đồng ý với tầm quan trọng của JavaScript khi giới thiệu khái niệm này, tôi nghĩ nhiều hơn là lập trình đồng thời, tôi sẽ đổ lỗi cho kiểu lập trình không đồng bộ hiện nay. Khi thực hiện các cuộc gọi async (cần thiết với các trang web), các hàm ẩn danh đơn giản rõ ràng rất hữu ích, mà mọi lập trình viên web (tức là mọi lập trình viên) đều phải làm quen với khái niệm này.


1

Một ví dụ thực sự cũ khác về một cái gì đó gần giống với các hàm ẩn danh / lambdas là tên gọi trong Algol 60. Lưu ý rằng tuy nhiên, tên gọi gần với việc truyền macro như tham số hơn là truyền các hàm thực và nó dễ vỡ / khó hơn hiểu như một kết quả.


0

Đây là tổ tiên để hiểu biết tốt nhất của tôi.

  • 2005: Javascript gần đây đã đưa lập trình bậc cao hơn với lambdas trở thành xu hướng. Trong các thư viện cụ thể như underscore.jsjquery . Một trong những người đầu tiên của các thư viện này là prototype.js đó xảy ra trước jquery khoảng năm. Nguyên mẫu dựa trên mô-đun vô số của Ruby, điều này dẫn chúng ta đến với
  • 1996: Mô-đun vô số của Ruby rõ ràng lấy cảm hứng từ khung bộ sưu tập của Smalltalk. Như Matz đã đề cập trong nhiều cuộc phỏng vấn, điều này dẫn chúng ta đến với
  • 1980: Smalltalk sử dụng nhiều lập trình bậc cao và cung cấp API bộ sưu tập sử dụng nhiều chương trình bậc cao (ví dụ: lớp Iterable của GNU Smalltalk ). Trong mã Smalltalk thành ngữ, bạn sẽ không tìm thấy bất kỳ vòng lặp nào mà chỉ liệt kê thứ tự cao. Thật không may khi Java khi khung bộ sưu tập của Smalltalk được chuyển sang Java vào năm 1998, các bảng liệt kê bậc cao hơn đã bị bỏ qua. Đó là cách lập trình bậc cao hơn đã được loại bỏ khỏi dòng chính trong mười năm tới! Smalltalk có nhiều tổ tiên, nhưng có liên quan đến câu hỏi của OP là LISP, điều này dẫn chúng ta đến với
  • 1958: LISP, rõ ràng, có lập trình bậc cao hơn ở cốt lõi của nó.

Amiss, tất nhiên, là toàn bộ tổ tiên ML. ML, SML, OCaml, Haskell, F #. Điều đó phải được tính cho một cái gì đó ..
Muhammad Alkarouri

-1

Các chức năng ẩn danh là tốt vì đặt tên mọi thứ rất khó và nếu bạn chỉ sử dụng một chức năng ở một nơi, thì nó không cần tên.

Các chức năng Lambda gần đây đã trở thành xu hướng vì cho đến gần đây, hầu hết các ngôn ngữ không hỗ trợ đóng cửa.

Tôi muốn đề xuất rằng Javascript đã đẩy dòng chính này. Đó là một ngôn ngữ phổ quát không có cách nào để diễn đạt song song và các chức năng ẩn danh dễ dàng sử dụng các mô hình gọi lại. Ngoài ra các ngôn ngữ phổ biến như Ruby và Haskell đã đóng góp.


1
"Các chức năng Lambda gần đây đã trở thành chính thống bởi vì cho đến gần đây, hầu hết các ngôn ngữ không hỗ trợ việc đóng cửa.": Lý do này nghe có vẻ hơi tròn đối với tôi: trở thành chính thống có nghĩa là hầu hết các ngôn ngữ đều hỗ trợ nó. Người ta có thể hỏi ngay "Điều gì đã kích hoạt sự phổ biến của việc đóng cửa trong các ngôn ngữ lập trình hiện đại".
Giorgio

Tôi biết rằng Python không có triển khai lambdas tốt nhất. Nhưng về mặt phổ biến, có lẽ nó đã đóng góp nhiều hơn Haskell.
Muhammad Alkarouri
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.