45 điểm bởi GN⁺ 2 ngày trước | 5 bình luận | Chia sẻ qua WhatsApp
  • Khác biệt giữa các cụm mẫu nền tảng quan trọng hơn các cú pháp riêng lẻ, và ngôn ngữ lập trình được chia thành bảy ngôn ngữ nguyên mẫu tùy theo cách lặp, đệ quy và tổ chức chương trình
  • ALGOL, Lisp, ML, Self, Forth, APL, Prolog là các phân loại cốt lõi; mỗi họ dùng một ngôn ngữ tiêu biểu làm mẫu chuẩn để xác định phả hệ của những ngôn ngữ khác
  • Một ngôn ngữ mới dùng chung ngôn ngữ nguyên mẫu quen thuộc thì khá dễ học, nhưng khi chuyển sang một nguyên mẫu xa lạ sẽ cần lối tư duy mới và khá nhiều thời gian học
  • ALGOL nổi bật với tổ chức hàm xoay quanh phép gán, câu lệnh điều kiện và vòng lặp; Lisp với macro và mã dưới dạng danh sách; ML với hàm hạng nhất và đệ quy; Self với đối tượng truyền thông điệp; Forth với cú pháp dựa trên ngăn xếp; APL với mảng n chiều; Prolog với cấu trúc sự kiện và tìm kiếm
  • Với mọi lập trình viên, ưu tiên trước hết là thành thạo ngôn ngữ thuộc họ ALGOL, sau đó học SQL, rồi tiếp tục đều đặn học các ngôn ngữ nguyên mẫu xa lạ sẽ có lợi hơn về dài hạn

Bảy ngôn ngữ nguyên mẫu của lập trình

  • Khi chọn ngôn ngữ lập trình, việc nắm các mẫu nền tảng quan trọng hơn khác biệt cú pháp riêng lẻ; giữa các ngôn ngữ cùng họ, những cấu trúc cơ bản như duyệt mảng hay duyệt tổ hợp gần như có cùng hình thức
  • Các họ ngôn ngữ khác nhau có sự khác biệt lớn về cách lặp, đệ quy và tổ chức chương trình; những cụm mẫu nền tảng này tạo thành các ngôn ngữ nguyên mẫu khác nhau
  • Học một ngôn ngữ mới cùng chia sẻ ngôn ngữ nguyên mẫu quen thuộc là một chuyển đổi tương đối dễ, nhưng khi chuyển sang một ngôn ngữ nguyên mẫu xa lạ thì sẽ cần đáng kể thời gian và những lối tư duy mới
  • Trong lĩnh vực phần mềm, các ngôn ngữ nguyên mẫu được công nhận có ALGOL, Lisp, ML, Self, Forth, APL, Prolog — tổng cộng bảy loại
  • Mỗi ngôn ngữ nguyên mẫu được phân loại dựa trên một ngôn ngữ đại diện cụ thể như một mẫu chuẩn, rồi các ngôn ngữ khác được xác định phả hệ bằng cách so sánh với mẫu đó
  • ALGOL

    • Chương trình được cấu thành từ chuỗi phép gán, câu lệnh điều kiện, vòng lặp và được tổ chức theo đơn vị hàm
    • Nhiều ngôn ngữ bổ sung vào đây hệ thống module, cách định nghĩa kiểu dữ liệu mới, đa hình, ngoại lệ hay các cấu trúc luồng điều khiển thay thế như coroutine
    • Phần lớn các ngôn ngữ lập trình được dùng rộng rãi hiện nay thuộc về họ ngôn ngữ nguyên mẫu này
    • Bản thân ALGOL bao gồm ALGOL 58, ALGOL 60, ALGOL W, ALGOL 68
    • Assembly language, Fortran, C, C++, Python, Java, C#, Ruby, Pascal, JavaScript, Ada đều nối với họ này
    • Đây là ngôn ngữ nguyên mẫu cổ nhất, có phả hệ truy ngược đến việc Ada Lovelace hình thức hóa chương trình cho máy phân tích của Babbage
    • Ngôn ngữ máy và hợp ngữ của các máy tính kiến trúc Eckert-Mauchly dẫn đến EDVAC và Univac đời đầu, cùng các thử nghiệm ngôn ngữ bậc cao ban đầu từ A-0 của Grace Hopper đến Fortran và COBOL đều thuộc dạng này
    • Trong giới học thuật thập niên 1960, lập trình cấu trúc phát triển để khiến các ngôn ngữ này dễ quản lý hơn; kết quả là ALGOL 60, và sau đó phần lớn các thành viên của họ này đều phái sinh từ đó
    • Theo thời gian, có xu hướng hấp thụ tính năng từ các ngôn ngữ nguyên mẫu khác
      • Trong thập niên 1980, các khái niệm từ họ Self được đưa vào dưới dạng lớp để làm phương tiện hiện thực định nghĩa kiểu dữ liệu và đa hình
      • Từ sau 2010, các khái niệm từ họ ML cũng xuất hiện
  • Lisp

    • Cú pháp kết hợp giữa biểu thức tiền tố đặt trong ngoặc và biểu diễn danh sách
      • (+ 2 3)
      • (defun square (x) (* x x))
      • (* (square 3) 3)
    • Biểu diễn danh sách là các mục được phân tách bằng khoảng trắng và bọc trong ngoặc được tích hợp sẵn vào ngôn ngữ, nên bản thân mã nguồn có dạng danh sách
    • Macro có thể nhận danh sách, sửa đổi nó rồi chuyển mã đã sửa cho trình biên dịch, tạo nên cấu trúc cho phép lập trình viên tái định nghĩa ý nghĩa của ngôn ngữ
    • Trong phần lớn việc viết mã, nó có xu hướng hoạt động giống các ngôn ngữ nguyên mẫu khác, thường là ALGOL hoặc ML, nhưng hệ thống macro là điểm phân biệt
    • Cú pháp loop của Common Lisp cũng không phải là tính năng tích hợp sẵn của ngôn ngữ mà được định nghĩa bằng macro
    • Ban đầu có nhiều biến thể Lisp, nhưng cộng đồng đã hình thành đồng thuận quanh Common Lisp
    • Sussman và Steele đã khám phá xem có thể làm được đến đâu chỉ với hàm, từ đó tạo ra Scheme
    • Các Lisp chuyên biệt như Lush cho tính toán số, AutoLISP là ngôn ngữ kịch bản của AutoCAD, và Emacs Lisp để hiện thực hành vi chỉnh sửa của Emacs cũng được sử dụng
    • Gần đây, Clojure nổi lên như nhánh lớn thứ ba của họ Lisp
    • Xuất hiện muộn hơn Fortran khoảng một năm, đây là họ ngôn ngữ lâu đời thứ hai vẫn còn được dùng đến ngày nay
    • Điểm khởi đầu là một câu hỏi toán học: làm sao biểu diễn một cấu trúc toán học có thể tự đánh giá các biểu thức của chính nó
    • John McCarthy đưa ra câu trả lời vào năm 1958, rồi sau đó nó được hiện thực trên máy tính
    • Lisp thời kỳ đầu, vì xuất phát từ nền tảng toán học, không khớp tốt với máy tính đương thời; các vấn đề về bộ nhớ và chu kỳ CPU không tồn tại trong toán học, nên cần đến những kỹ thuật như garbage collection
    • Cuối thập niên 1970 và đầu thập niên 1980 từng tồn tại những cỗ máy được thiết kế từ nền móng chỉ để chạy Lisp
    • Nhiều yếu tố của môi trường phát triển tích hợp ngày nay được phát minh trên các cỗ máy đó
    • Cùng thời kỳ, Lisp là công cụ chủ đạo của nghiên cứu trí tuệ nhân tạo; khi cơn sốt AI thập niên 1980 không tạo ra kết quả, Lisp cũng cùng lĩnh vực rơi vào AI Winter
    • Dù vậy, nó vẫn sống sót, và nhờ năng lực máy tính tăng lên cùng việc các ngôn ngữ khác tiếp nhận các tính năng của nó, độ khó khi hiện thực đã giảm đi
  • ML

    • Hàm là giá trị hạng nhất, và ngôn ngữ có hệ thống kiểu thuộc họ Hindley-Milner cho phép biểu diễn nhiều loại hàm và tagged union
    • Mọi phép lặp đều được thực hiện bằng đệ quy
      • sum [] = 0
      • sum (x:xs) = x + sum xs
    • Cũng dùng cách định nghĩa các hàm đóng gói mẫu lặp rồi nhận hàm khác làm đầu vào để triển khai hành vi
      • map _ [] = []
      • map f (x:xs) = (f x) : (map f xs)
    • Một số ngôn ngữ như Miranda và Haskell mặc định dùng đánh giá trì hoãn
    • Các ngôn ngữ khác mở rộng hệ thống kiểu theo nhiều hướng
      • OCaml thử kết hợp với các khái niệm của ngôn ngữ nguyên mẫu Self
      • Agda và Idris áp dụng hệ thống kiểu phụ thuộc trộn lẫn giá trị với kiểu
      • 1ML kết hợp module và kiểu
    • Từ ML đã phái sinh ra CaML, Standard ML, OCaml
    • Các họ liên quan như Miranda, Haskell, Agda, Idris cũng tiếp nối từ đây
    • ML vốn là meta-language của một chương trình chứng minh định lý được phát triển tại Cambridge, Anh, và tên gọi cũng bắt nguồn từ đó
    • Sau đó nó vượt ra ngoài bối cảnh ban đầu và lan rộng như một ngôn ngữ độc lập, đặc biệt được ưa chuộng ở châu Âu, nhất là tại Anh và Pháp
  • Self

    • Chương trình được cấu thành từ một tập hợp đối tượng gửi thông điệp cho nhau, và mọi hành vi đều được hiện thực theo cách này
    • Đối tượng mới được tạo ra bằng cách gửi thông điệp đến đối tượng hiện có
    • Ngay cả câu lệnh điều kiện cũng được thực hiện thông qua một biến tham chiếu đến một trong hai đối tượng true hoặc false
      • Hai đối tượng này nhận một thông điệp với tham số là hàm sẽ chạy khi đúng và hàm sẽ chạy khi sai
      • Đối tượng true thực thi hàm thứ nhất, còn đối tượng false thực thi hàm thứ hai
      • Mã gọi không biết đó là đối tượng nào, mà chỉ đơn thuần gửi thông điệp
    • Vòng lặp cũng hoạt động theo cách tương tự; nếu tạo đúng đối tượng và đặt nó vào đúng vị trí thì có thể tái định nghĩa toàn bộ ý nghĩa của ngôn ngữ
    • Các ngôn ngữ kiểu này thường không lưu mã nguồn dưới dạng tệp văn bản mà trong một môi trường sống
    • Lập trình viên chỉnh sửa trực tiếp hệ thống đang chạy và lưu trạng thái đó, thay vì biên dịch tệp để tạo ra hệ thống
    • Những ví dụ quan trọng là Smalltalk và Self
    • Nhiều ngôn ngữ chỉ tiếp nhận một phần cách truyền thông điệp của họ ngôn ngữ này, và cách tiếp nhận từng phần đó thường được gọi là lập trình hướng đối tượng
    • Phần lớn trong số đó dựa trên Smalltalk; chỉ riêng JavaScript là ngoại lệ, bắt nguồn từ hệ đối tượng không lớp của Self
    • Hệ thống đối tượng của Common Lisp khái quát hóa thêm: thay vì chỉ một đối tượng nhận thông điệp, runtime chọn mã thực thi dựa trên mọi tham số
    • Erlang chuyển sang hướng các luồng thực thi song song nghe và gửi thông điệp một cách tường minh, thay vì luồng thực thi di chuyển giữa các đối tượng
    • Ngôn ngữ gốc là Smalltalk, được phát triển tại Xerox Parc vào cuối thập niên 1970 và trong thập niên 1980
    • Trong thập niên 1980 từng có nhiều hệ Smalltalk thương mại, và IBM cũng dùng Smalltalk để phát triển bộ công cụ lập trình VisualAge cho các ngôn ngữ khác
    • Ngày nay Smalltalk chủ yếu còn tồn tại dưới dạng mã nguồn mở Pharo Smalltalk
    • Đã có nhiều nghiên cứu về cách chạy Smalltalk nhanh và hiệu quả, và đỉnh cao của chúng là dự án Strongtalk
    • Về mặt lịch sử, phát hiện từ Strongtalk đã trở thành nền tảng cho trình biên dịch JIT HotSpot của Java
    • Smalltalk kế thừa khái niệm giá trị và kiểu từ các ngôn ngữ trước đó để hiện thực lớp; mọi đối tượng đều có một lớp gán kiểu cho nó, và lớp tạo ra đối tượng của kiểu đó
    • Self loại bỏ khái niệm lớp và chỉ còn các đối tượng
    • Vì là hình thức thuần hơn, Self được chọn làm mẫu tiêu biểu của ngôn ngữ nguyên mẫu này
  • Forth

    • Ngôn ngữ ngăn xếp có thể xem như ảnh gương của Lisp, và chia sẻ cú pháp với các máy tính cầm tay ký pháp Ba Lan ngược của Hewlett Packard
    • Nó có một ngăn xếp dữ liệu; khi viết literal như 42 thì giá trị được đẩy lên ngăn xếp, còn tên hàm hoạt động trên ngăn xếp mà không có tham số tường minh
    • Ngay cả phép toán đơn giản cũng có dạng đảo ngược như 2 3 + 5 *
    • Định nghĩa hàm cũng rất cô đọng
      • Trong phần lớn biến thể Forth, : dùng để định nghĩa một từ mới
      • square có nghĩa là gọi dup rồi *
      • dup sao chép phần tử trên cùng của ngăn xếp, còn * nhân hai phần tử trên cùng
    • Có thể chặn parser và thay nó bằng mã của chính mình, nên toàn bộ cú pháp có thể bị thay thế
    • Rất thường gặp các chương trình Forth định nghĩa những ngôn ngữ nhỏ, như một tập con của Fortran, mô tả bố cục gói tin, hoặc cách phân tích trực tiếp sơ đồ ASCII biểu diễn chuyển trạng thái của máy trạng thái
    • Bao gồm nhiều biến thể của Forth, cùng PostScript, Factor, Joy
    • Joy là một ngôn ngữ hàm thuần dùng hình thức toán học của phép hợp thành thay cho ngăn xếp
    • Forth lần đầu được viết vào năm 1970 để điều khiển kính thiên văn vô tuyến
    • Sau đó nó lan rộng khắp lĩnh vực hệ thống nhúng
    • Hệ thống Forth đủ dễ bootstrap nên tồn tại hàng chục biến thể do nhiều lập trình viên tự tạo để phục vụ mục đích riêng
    • PostScript xuất hiện trong thập niên 1980 như một phương tiện linh hoạt để mô tả tài liệu cho máy in
    • Xét trên nhiều phương diện PostScript bị giới hạn hơn Forth, nhưng nó định nghĩa sẵn trong ngôn ngữ các phép toán cơ bản liên quan đến bố cục đồ họa
  • APL

    • Mọi thứ trong ngôn ngữ đều là mảng n chiều
    • Toán tử được tạo từ một hoặc hai ký hiệu và thực hiện các phép toán cấp cao trên toàn bộ mảng
    • Biểu đạt cực kỳ cô đọng, đến mức chính chuỗi ký hiệu đã là dấu hiệu của phép toán mà không cần đặt tên khác
    • Ví dụ, để tính trung bình của biến x thì viết (+⌿÷≢) x
    • APL, J, K là các trường hợp tiêu biểu
    • Các phép toán bậc cao trên mảng đã được “xuất khẩu” một phần sang nhiều môi trường như MATLAB, NumPy, R
    • APL bắt đầu từ ký pháp toán học do Kenneth Iverson tạo ra trong thập niên 1960, rồi sau đó mới được hiện thực trên máy tính
    • Từ đó đến nay nó luôn duy trì được một cộng đồng ủng hộ ngách trong giới làm tính toán nặng
    • Ngôn ngữ hậu duệ K từng rất được ưa chuộng trong môi trường tài chính
  • Prolog

    • Chương trình được cấu thành từ một tập các sự kiện
      • father(bob, ed).
      • father(bob, jane).
    • Cũng dùng sự kiện chưa cố định giá trị để suy ra sự kiện từ các sự kiện khác bằng biến
      • grandfather(X, Y) :- father(X, Z), father(Z, Y).
    • Runtime của Prolog nhận các sự kiện này cùng truy vấn rồi thực hiện tìm kiếm để tìm ra kết quả
    • Nếu chọn cấu trúc định nghĩa sự kiện phù hợp thì sẽ đạt được tính Turing đầy đủ
    • Trong Prolog, các term tạo nên sự kiện bản thân chúng là một kiểu dữ liệu riêng biệt và có thể được tạo ra rồi chuyển cho runtime
    • Điểm này giữ vị trí tương tự macro trong Lisp hay việc thay parser trong Forth
    • Vì chương trình Prolog về bản chất là tìm kiếm, việc tinh chỉnh xoay quanh điều chỉnh thứ tự tìm kiếm và cắt sớm các nhánh không đem lại kết quả, giống như truy vấn cơ sở dữ liệu
    • Bao gồm Prolog, Mercury, Kanren
    • Phần lớn lập trình thực tế trong họ ngôn ngữ nguyên mẫu này diễn ra ngay trên Prolog, và cộng đồng có mức độ thống nhất rất cao
    • Trong thập niên 1970, các nhà logic học Pháp nhận ra rằng có thể biểu diễn chương trình bằng logic bậc nhất và bắt đầu thử hiện thực nó
    • Trong thập niên 1980, dự án máy tính thế hệ thứ năm của Nhật Bản đặt cược lớn vào Prolog, nhưng khi dự án thất bại thì danh tiếng của Prolog cũng suy giảm theo
    • Tuy vậy, suốt hàng chục năm vẫn có nghiên cứu nhằm làm cho runtime Prolog hiệu quả trong đa số trường hợp và bổ sung các tính năng mới
    • Các tính năng như ràng buộc số học được thêm vào, dẫn đến lập trình logic ràng buộc
    • Prolog vẫn tiếp tục xuất hiện trong những lĩnh vực ngách
      • Trình kiểm tra kiểu của Java từng được hiện thực bằng Prolog trong nhiều năm
      • Công cụ tìm kiếm mã nguồn ban đầu của Facebook cũng dựa trên Prolog

Nên tận dụng điều này như thế nào

  • Với phần lớn lập trình viên, một phần hoặc toàn bộ các họ ngôn ngữ này có thể trông rất xa lạ, nhưng vẫn đáng bỏ ra một khoảng thời gian vì lối tư duy và những khả năng mới mà mỗi loại mang lại
  • Từ góc nhìn ALGOL, hai đối tượng có vẻ hoàn toàn khác nhau thường lại chỉ là một so sánh vụn vặt dưới góc nhìn khác
  • Ưu tiên

    • Mọi lập trình viên đều nên nắm vững một ngôn ngữ thuộc họ ALGOL
    • Sau đó nên học SQL, một ngôn ngữ thuộc họ Prolog
      • Xét trong sự nghiệp, đây là thứ đem lại hiệu dụng lớn thứ hai sau ALGOL
  • Mở rộng tiếp theo

    • Sau khi đã học hai họ trên, về dài hạn sẽ có lợi nếu mỗi năm học thêm một ngôn ngữ mới thuộc một họ nguyên mẫu xa lạ
    • Các ngôn ngữ được gợi ý cho từng họ và thứ tự là như sau
      • Lisp: PLT Racket
      • ML: Haskell
      • Self: Self
      • Prolog: Prolog
      • Forth: gForth
      • APL: K, dùng qua ok
  • Điều chỉnh thứ tự

    • Nếu làm nhiều tính toán số, sẽ phù hợp hơn nếu học K sớm hơn
    • Nếu làm nhiều lập trình nhúng, sẽ phù hợp hơn nếu học gForth sớm hơn
    • Tuy nhiên, bản thân thứ tự hay việc chọn chính xác ngôn ngữ nào không phải điều quan trọng
    • Có thể học Standard ML hoặc OCaml thay cho Haskell, Common Lisp thay cho PLT Racket, hay Factor thay cho gForth đều được
  • Phần bổ sung trong chú thích

    • Ngay cả sau khi học SQL, vẫn cần học Prolog
      • Vì cách sử dụng thực tế của nó khá khác với SQL
    • Một ý kiến của độc giả cho rằng để hiểu sâu Forth, cách làm phổ biến là tự viết một trình hiện thực Forth
      • Có nhắc rằng Forth đủ nhỏ để một người có thể hiện thực từ nền móng trong thời gian tương đối ngắn
      • gForth là một trình hiện thực phù hợp để học ANS Forth
      • Tài liệu học được nhắc đến là FORTH Fundamentals, Volume 1 của McCabe
      • Các biến thể Forth nên xem thêm gồm PygmyForth, eForth, colorForth

5 bình luận

 

Thú vị đấy.

 

Hồi đại học tôi đã học các môn chuyên ngành và làm bài tập với họ ALGOL, Lisp và Prolog, nên đọc lại thấy thật bồi hồi.

 

Những ngôn ngữ đó đã để lại rất nhiều dấu ấn trong các ngôn ngữ lập trình chủ lưu hiện đại,
nhưng trong số đó chỉ có Forth là có vẻ như ảnh hưởng ít hơn.

 

Dù không cần đến ký pháp tiền tố, nhưng nếu phải code bằng ký pháp hậu tố thì đúng là quá bất tiện.

 
Ý kiến trên Hacker News
  • Trong lớp PL ở Tufts, họ đã tự tay làm các phiên bản mini của 4 họ ngôn ngữ đầu tiên là mệnh lệnh, Lisp, ML, Smalltalk, và thật vui khi quá trình đó giờ cũng đã có thành giáo trình. Hơi tiếc là trước đây còn có cả phần Prolog nhưng giờ đã bị bỏ đi

    • Nếu có bản nào gồm cả phần Prolog bị lược bỏ được đưa lên Internet Archive hay đâu đó thì sẽ rất tuyệt
  • Nếu chỉ sửa đúng một điểm trong cách phân loại của bài này, thì tôi cho rằng Ruby rõ ràng là một ngôn ngữ hướng đối tượng hơn là thuộc họ Algol. Nó chịu ảnh hưởng lớn từ Smalltalk, và ngay cả tên thư viện chuẩn cũng còn dấu vết đó, kiểu dùng collect thay vì map. Trong Ruby, từ đầu đến cuối mọi thứ đều là đối tượng, và hiểu lời gọi phương thức như việc gửi thông điệp tới một đối tượng là cách nhìn tự nhiên hơn. Nó thường bị so với Python, nhưng con đường tiến hóa khá khác nhau, và giờ có cảm giác như đã hội tụ về những điểm tương tự trong hệ sinh thái. Với tôi, Ruby giống một con alpaca ấm áp hơn Python

    • Thực ra Python, kể từ new style classes, cũng có thể xem là một ngôn ngữ OOP thuần túy. Ở mức Hello World thì điều đó ít lộ rõ, nhưng ngay cả các kiểu cơ bản cũng đều đã là đối tượng. Với những người không thích OOP, cho họ xem type(42)dir(42) là cách hay để nhấn mạnh rằng ngay cả số nguyên cũng là đối tượng
    • Tôi lại thấy việc chỉ đích danh một ngôn ngữ nguyên mẫu nào đó là ngôn ngữ hướng đối tượng còn dễ làm mọi người bối rối hơn. OO, giống như thủ tục, gần hơn với một phong cách lập trình; gom Python và C++ vào cùng một loại ngôn ngữ chỉ vì cả hai có đa kế thừa thì tôi thấy khá gượng ép
    • Nói đến ví von lạc đà thì hình như camel vốn là biểu tượng bên Perl chứ nhỉ
  • Tôi muốn thêm vào hệ phả ngôn ngữ một nhóm nữa là ngôn ngữ biểu diễn chứng minh. Đây là dòng mà chương trình cũng chính là chứng minh theo tương ứng Curry-Howard, và Lean là ví dụ tiêu biểu. Có thể xem như một phân nhánh con của hàm, nhưng vì mục tiêu chính là kiểm chứng hơn là thực thi, tôi thấy đáng để tách thành một trục riêng

    • Trong mắt tôi, chứng minh định lý và các kiểu phức tạp trông giống như những phần mở rộng gắn lên các ngôn ngữ sẵn có. Agda, Idris là ngôn ngữ hàm với kiểu phức tạp được bổ sung; Isabelle và Lean thì thêm cả chứng minh tương tác. Dafny nghiêng về phía mệnh lệnh được gắn thêm định lý và gợi ý, còn ACL2 thì dễ hiểu nếu xem là Lisp có thêm theorem/hint. Ngoài ra, như ở Rust traits, typeclasses cũng tạo cảm giác như một dạng lập trình logic chạy trên các ngôn ngữ hàm và mệnh lệnh
    • Theo định nghĩa thì nhóm này không có tính đầy đủ Turing, nên tôi thấy khó coi đó là ngôn ngữ lập trình đúng nghĩa. Nếu nó đầy đủ Turing, thì có thể tạo ra chứng minh sai bằng một chương trình không bao giờ kết thúc
    • Tôi cho rằng dòng này rốt cuộc phái sinh trực tiếp từ ML
    • Lean rõ ràng là một ngôn ngữ thuộc họ ML với kiểu phụ thuộc, rất gần Agda và Idris, nên nhìn rộng ra thì hoàn toàn có thể đặt trong phân loại ML. Và mục tiêu dài hạn của Lean dường như cũng không phải kiểu xem thực thi là thứ yếu. Microsoft đang quan tâm tới việc viết phần mềm thực tế. Ngược lại, nếu nhấn mạnh hơn vào khía cạnh “ngôn ngữ để biểu diễn chứng minh” thì cũng không thể bỏ qua Prolog, nên có thể xem Lean là nửa ML, nửa Prolog. Theo góc nhìn này, tương ứng Curry-Howard giống như một cách để hiện thực logic tính toán
  • Gần đây tôi xem lại một dự án so sánh ngôn ngữ, với benchmark là phân rã chu trình song song trên 3,715,891,200 signed permutation của 10 ký tự. Thứ tôi muốn tìm không hẳn là “ngôn ngữ nguyên mẫu”, mà là trong các hiện thực hiện đại của từng hệ hình thì ngôn ngữ nào thực sự đáng chọn cho kiểu lập trình nghiên cứu này. Tôi xem không chỉ hiệu năng, mà cả việc có dễ nhận trợ giúp từ AI hay không, và bản thân tôi có dễ đọc hiểu, suy nghĩ về mã hay không; nhờ AI, tôi cũng có thể đi một vòng tham quan khá sâu để tối ưu từng ngôn ngữ. Kết quả được tổng hợp ở đây, và việc F# đứng đầu quả thật khá bất ngờ

    • Nhìn thoáng qua thì có vẻ lạ, nhưng tôi nghĩ chi tiết mới là cốt lõi. Nếu bỏ Lean ra thì nhìn chung chênh lệch không quá kịch tính, và việc Chez chậm hơn C++ 2.5 lần cũng là một kết quả khá tốt đối với một ngôn ngữ JIT kiểu động. F# mạnh trong loại tác vụ này có lẽ phần lớn vì kinh nghiệm xử lý song song trên .NET Core đã rất chín muồi và ổn định. Nếu con số đó là elapsed time thì sẽ càng thú vị hơn nếu có thêm phân rã theo CPU time. Ngoài ra, chiến lược song song hóa giữa các ngôn ngữ cũng hơi khác nhau, nên đây không hoàn toàn là so sánh trong điều kiện giống hệt. Ví dụ, phân nhánh thread đơn giản ở F# và parallel iterator của Rust Rayon có thể có cấu trúc overhead khác nhau. Rốt cuộc Rust và C++ có thể còn nhanh hơn nếu chăm chút kỹ các primitive đồng thời mức thấp của OS, nhưng như vậy lại thành một kiểu so sánh khác. Cũng khó nói có nên cho phép dùng C FFI trong C hay Haskell hay không, nên các kiểu so sánh thế này vốn dĩ luôn pha nhiều đánh giá định tính. Nhân tiện, mã Chez có vẻ còn có thể nhanh hơn nếu chứa permutation trong fxvector và dùng các phép toán chuyên cho fixnum để giảm boxing/unboxing và cấp phát. Tài liệu liên quan nằm ở tài liệu đối tượng của Chez Scheme
  • Tôi cũng từng viết một bài tương tự ở đây. Tôi đồng ý với Algol, Lisp, Forth, APL, Prolog, nhưng với ngôn ngữ hàm mang tính đột phá thì tôi chọn SASL, ra đời sớm hơn ML một chút, còn đại diện cho hướng đối tượng thì tôi chọn Smalltalk, có trước Self. Ngoài ra tôi còn thêm Fortran, COBOL, SNOBOL và Prograph vì cho rằng mỗi ngôn ngữ đều đã thay đổi cuộc chơi theo cách riêng

    • Tôi thích danh sách này hơn. Đặc biệt vui khi thấy có SNOBOL. Tôi chưa từng dùng nó, nhưng hồi nhỏ trong một đợt bán sách thanh lý ở thư viện công cộng, tôi biết tới nó chỉ vì cái tên nghe thú vị nên cầm lên xem một cuốn sách về nó. Trước đó tôi mới chỉ biết BASIC, Logo, và một chút hợp ngữ 6502 được gọi từ BASIC bằng cách làm theo ví dụ trong hướng dẫn Atari BASIC. Tôi cũng khó tưởng tượng một danh sách ngôn ngữ đột phá mà lại thiếu Fortran và COBOL, hoặc gốc rễ của chúng là FLOW-MATIC. Cuốn tôi tham khảo là Atari BASIC manual
    • Tôi không hiểu vì sao Smalltalk lại không vào danh sách thay vì Self. Smalltalk có trước, và Alan Kay cũng chính là người đặt ra cái tên “OOP”. Còn ML thì tôi cũng thiên về xem nó là con của Lisp trong hệ phả
  • Tôi muốn thêm vào thảo luận này các họ ngữ nghĩa nữa. Ví dụ như Verilog, Petri nets, Kahn process networks, dataflow machines, process calculi, reactive, term rewriting, các họ constraint solver/theorem prover, probabilistic programming. Cũng có những ngôn ngữ không khớp gọn với 7 nhóm hiện có nhưng thực tế đã khá gần mức production như Unison, Darklang, temporal dataflow, DBSP. Nghe có vẻ hơi gian lận, nhưng phần lớn trong số đó là các mô hình tính toán song song với mô hình máy von Neumann. Từ lâu tôi đã muốn viết một bài kiểu “mọi cách tính toán mà ta biết, vượt ra ngoài von Neumann”

    • Nếu có bài như vậy thì tôi sẽ rất vui mà đọc. Trong lúc đó, nó làm tôi nhớ lại một phần bài viết của Steve Yegge. Ý chính là phần lớn giáo dục CS hiện đại thực ra đang xây trên cái khung do von Neumann tạo ra, và việc chọn thiết bị tuần tự cũng phản ánh thực tế chi phí chế tạo và tốc độ vào thời đó. Tôi cũng ấn tượng với ý rằng rất nhiều thứ chúng ta học như kiến trúc máy, rẽ nhánh, lặp, chương trình con, gỡ lỗi, chuyển đổi hệ số, mô hình hóa bài toán... đều đã xuất hiện trong công trình của ông. Trích dẫn liên quan ở archive
    • Nhắc đến term rewriting làm tôi nhớ hồi đại học làm phần mềm bảng tính và phụ trách parser công thức. Ban đầu tôi kẹt cả tuần, rồi cuối cùng nhận ra rằng chỉ cần viết lại 1+1 thành dạng như ADD(1,1) thì tôi có thể parse theo cách mình đã biết. Thêm nữa là tôi đã vô lý từ chối học regex nên mã trở nên khá kỳ quặc, và tôi vẫn còn nhớ đồng nghiệp nói “Andy bảo làm được thì cứ để cậu ấy làm”. Một người ở nhóm khác thì dùng regex và giải quyết xong với lượng mã ngắn hơn của tôi cỡ 20 lần
    • Nhân chuyện “ngôn ngữ mới nổi sẵn sàng cho thực chiến”, theo tiêu chuẩn của tôi thì ngay cả những hệ như ChatGPT tuy có thể chưa hoàn toàn production-ready theo mọi nghĩa, nhưng vẫn thuộc một nhóm tương tự vì chúng đang được dùng trong công việc thực tế. Việc có xem chúng là ngôn ngữ lập trình hay không thì còn tranh cãi, nhưng xét ở góc độ chúng là phương tiện để con người bảo máy tính làm gì đó, tôi nghĩ hoàn toàn có thể xem như vậy. Tính không quyết định cũng không nhất thiết loại chúng khỏi phạm trù ngôn ngữ lập trình
    • Tôi cũng nghĩ bài viết của Sussman về propagators rất đáng đọc
    • Về ví dụ logic programming trong S9 Scheme thì tài liệu này khá ổn. Không nhất thiết phải mua sách, bạn có thể tải mã ngay; chỉ cần học nền tảng qua một sách nhập môn như Simply Scheme rồi áp dụng thì cấu trúc của bộ giải khá dễ đọc
  • Môn “Concepts of programming languages” ở TU Delft là môn tôi thích nhất trong cả chương trình khoa học máy tính. Chúng tôi học C, phía hàm thì dùng Scala, và JavaScript cho khái niệm prototype; nhờ vậy mà vài năm sau khi học Elixir tôi thấy dễ hơn hẳn. Ngoài ra còn có một môn viết agent cho Unreal Tournament bằng GOAL, một ngôn ngữ dựa trên Prolog. Trong thời gian dài tôi không biết nên dùng Prolog vào việc gì, nhưng cuối cùng lại dùng nó để làm một spellcheck buộc các câu Papiamentu tệ do LLM sinh ra phải được sửa lặp đi lặp lại

    • Tôi cũng học một lớp tương tự, và dù giáo sư không hay lắm thì tôi vẫn thấy đăng ký là quyết định rất đúng. Chỉ cần biết dù rất sơ qua về các ngôn ngữ nguyên mẫu khác nhau thôi cũng đã mở rộng tầm nhìn đáng kể, và nếu thêm cả hợp ngữ nữa thì hiệu ứng còn rõ hơn. Dù có thể không trực tiếp dùng chúng để làm gì năng suất, ít nhất bạn cũng tránh được cái bẫy cầm búa rồi thấy việc gì cũng như cái đinh
    • Tôi cũng có trong lớp đó. Phần Unreal Tournament là một trong những môn học ngầu nhất tôi từng thấy, và tôi nhớ là sang năm sau thì nó bị bỏ. Giờ hình như nó đã thành một lớp AI bình thường như ai cũng có, khá đáng tiếc. Tôi vẫn chưa tìm được nhiều chỗ dùng Prolog thật sự hay, nhưng GOAL thì để lại ấn tượng mạnh hơn nhiều. Và chỉ gần đây tôi mới nhận ra rằng cấu trúc đó hoàn toàn có thể tái tạo trong những ngôn ngữ “bình thường” hơn, mà làm vậy còn có nhiều lợi ích, nên cũng hơi hụt hẫng
    • Tôi tò mò không biết GOAL ở đây có phải là Game Oriented Assembly Lisp không
  • Tôi đồng ý với quan điểm “nên học các ngôn ngữ thuộc những nhóm khác nhau”. Chỉ sau khi học OCaml tôi mới thực sự cảm thấy hàm giống hàm toán học, còn Mathematica thì rèn cho tôi thói quen nhìn biểu thức như chính dữ liệu đầu vào. Ký pháp Ba Lan ngược của PostScript không chỉ thay đổi cách làm số học đơn giản mà gần như còn đi lại dây toàn bộ cách suy nghĩ. Tuy vậy, tôi không đồng ý với ý cho rằng chọn Java, C#, C++, Python hay Ruby đều như nhau. Nếu mục tiêu chỉ là cài quicksort thì có thể tương tự, nhưng với người thực sự muốn xây thứ gì đó, lựa chọn ngôn ngữ tạo ra khác biệt một trời một vực. Đưa Ruby cho người muốn làm game 3D, hay đưa Java cho người muốn làm khoa học dữ liệu khám phá hoặc deep learning, có thể làm họ mất động lực

    • Có lẽ tôi sẽ không bao giờ kiếm tiền bằng Rust, nhưng tôi hoàn toàn không hối hận vì đã học nó. Rust khiến tôi phải suy nghĩ rất sâu về quyền sở hữu dữ liệu trong một chương trình
  • Bài này làm tôi nhớ tới 7 languages in 7 weeks của Bruce Tate. Tôi cũng biết đến Erlang lần đầu qua cuốn đó. Dù vậy, về mặt lịch sử thì xếp COBOL và Fortran vào họ Algol có phần hơi gượng, nhưng ít nhất nó cũng nhắc ta rằng lịch sử vốn dĩ luôn là một sự giản lược ở mức nào đó

    • Tôi còn thấy việc cố truy ngược để lập một phân loại nguyên thủy như vậy cũng khá gượng. Các ngôn ngữ assembly đầu tiên cũng là mệnh lệnh, nhưng điều làm Algol, Fortran và Cobol thú vị là chúng đã cho phép lập trình phức tạp nhờ hàm và các tính năng mức cao khác. Hậu duệ của Algol là đông nhất, nhưng nếu hỏi ngôn ngữ lập trình mệnh lệnh đầu tiên thì tôi nghĩ là Fortran
    • Chỉ nhìn Wikipedia thì Fortran và Algol có vẻ đều được phát triển quanh năm 1957, nhưng tôi tò mò không biết thực tế bên nào ra trước, và trong quá trình thiết kế có ảnh hưởng qua lại hay chồng lấn gì không
    • Có khi đúng hơn nên xem COBOL như một hóa thạch sống. Còn Fortran ngày nay cho tôi cảm giác là một ngôn ngữ dựa trên dòng FORTRAN nhưng đã tiếp nhận theo kiểu chuyển giao ngang nhiều đặc điểm của hệ Algol
  • Trước đây cũng đã có thảo luận HN liên quan. Xem thêm cuộc thảo luận trước sẽ giúp nắm bối cảnh tốt hơn

    • Chính xác là cuộc thảo luận ngày 4/5/2023 với 323 bình luận. Còn cũ hơn nữa là chuỗi này ngày 30/9/2021, khi đó có 29 bình luận