Ngôn ngữ lập trình Racket
(racket-lang.org)- Racket là một ngôn ngữ trưởng thành đặt lập trình hướng ngôn ngữ ở trung tâm, xử lý cả phát triển ứng dụng thông thường lẫn tạo ngôn ngữ mới trong cùng một hệ sinh thái
- Cốt lõi là macro và
#lang, cho phép tạo cú pháp mới, ngôn ngữ chuyên biệt theo miền và cú pháp bề mặt hiện có như thư viện, rồi dùng theo đơn vị mô-đun - Thư viện chuẩn bao gồm từ web server, cơ sở dữ liệu, toán học·thống kê, GUI đến mô phỏng khoa học, cùng hàng nghìn package mở rộng phạm vi phát triển đa mục đích
- Typed Racket, contract, hệ thống đối tượng và IDE DrRacket được cung cấp cùng nhau, cho phép kết hợp mã hàm, thành phần hướng đối tượng và kiểu dần dần tùy nhu cầu
- Racket không chỉ là một ngôn ngữ họ Lisp đơn thuần, mà gần với một môi trường phát triển nhằm tạo ngôn ngữ phù hợp cho từng lĩnh vực vấn đề và kết nối cả chạy, chỉnh sửa lẫn hỗ trợ công cụ
Racket cho lập trình hướng ngôn ngữ
- Racket là một ngôn ngữ lập trình đồng thời nhấn mạnh “Racket, the Programming Language” và “Racket, the Language-Oriented Programming Language”
- Racket version 9.2 hiện đã có thể sử dụng
- Đây là một sản phẩm trưởng thành đã hỗ trợ lập trình đồ họa đa nền tảng trên Windows, macOS và Linux từ rất sớm
- Các chức năng phát triển cơ bản bao gồm quản lý package, GUI, binary thực thi độc lập và giao diện với bên ngoài
Phạm vi phát triển ứng dụng thông thường
- Racket có bộ thư viện bao phủ từ ứng dụng web server đến toán học và phần mềm mô phỏng khoa học
- Các tài liệu và phạm vi thư viện tiêu biểu như sau
- Bộ công cụ GUI đa nền tảng và web server được đưa vào hệ sinh thái cơ bản
- Có thể cài đặt hàng nghìn package bổ sung chỉ bằng một lệnh
- Ví dụ gồm 3D graphics, Bluetooth socket connector, color maps, data structures, educational software, games, quantum-random number generator, scientific simulations, web script testing, v.v.
- Ví dụ
#lang racket/guitriển khai một trò chơi đoán số nhỏ bằng phương ngữ GUI và sử dụng nhiều tính năng ngôn ngữ cùng lúc
Ngôn ngữ được mở rộng bằng macro
- Lập trình viên Racket có thể dùng macro để định nghĩa vòng lặp riêng và cú pháp mới
- Cú pháp mới được thêm vào như procedure, method và class; chỉ cần tạo quy tắc viết lại cú pháp tùy chỉnh thành biểu thức hoặc định nghĩa Racket
- Macro nhỏ giúp loại bỏ mã lặp vốn khó xử lý bằng các tính năng khác
- Có thể định nghĩa cú pháp
time-itđể đo thời gian thực thi tác vụ - Có thể tránh việc dùng
lambdalặp đi lặp lại - Macro được export từ mô-đun như hàm thông thường
- Có thể định nghĩa cú pháp
- Toàn bộ hệ thống macro cũng có thể tạo cấu trúc trong đó nhiều macro phối hợp với nhau
- Racket là ngôn ngữ hàm, nhưng ngay từ đầu đã cung cấp ngôn ngữ con cho classes and objects, mixins and traits
- Hệ thống class tương tự Java được triển khai dưới dạng thư viện dựa trên macro, hoạt động mà không cần hỗ trợ riêng từ ngôn ngữ lõi
#lang và ngôn ngữ chuyên biệt theo miền
- Racket hướng tới vai trò ngôn ngữ để tạo ngôn ngữ, cho phép lập trình viên viết từng mô-đun bằng ngôn ngữ phù hợp
- Ví dụ
#lang typed/racketsử dụng union type củaStringvàNumber, occurrence typing và lọc danh sách - Ví dụ
#lang scribble/basexử lý ngôn ngữ tài liệu tạo tài liệu PDF hoặc HTML - Ví dụ
#lang datalogdùng cú pháp Datalog để định nghĩa và truy vấn quan hệparentvàancestor - Có thể tạo ngôn ngữ mới trong một cửa sổ IDE và chạy mô-đun của ngôn ngữ đó trong cửa sổ IDE khác, không cần thiết lập, file dự án hay công cụ bên ngoài
- Người dùng Racket chủ yếu dùng cú pháp ngoặc, nhưng cũng có thể tạo cú pháp bề mặt hiện có cần dấu phẩy và dấu ngoặc nhọn như Datalog
- Khi dùng parsing packages, có thể ánh xạ ngữ pháp tùy ý sang ngôn ngữ dựa trên ngoặc và biên dịch thành Racket thông thường bằng hệ thống macro của Racket
DrRacket và hệ sinh thái phát triển
- Racket cung cấp IDE riêng là DrRacket, có tính năng vẽ mũi tên tới vị trí định nghĩa khi di chuột lên định danh
- Ngay cả khi dùng ngôn ngữ thay thế như Typed Racket, vẫn có thể tận dụng hỗ trợ chỉnh sửa của DrRacket
- Macro của Racket ghi lại và truyền đủ thông tin nguồn ngay cả trong các macro phức tạp hoặc macro tạo ngôn ngữ mới, để DrRacket có thể hoạt động như thể hiểu các tính năng của ngôn ngữ mới
- Các hỗ trợ phát triển chính như sau
- Tài nguyên hệ sinh thái bao gồm tải xuống, mã nguồn, báo cáo lỗi, nightly snapshot builds và kho package
- Tài liệu học tập và tài liệu tham khảo gồm Quick Introduction, The Racket Guide, The Racket Reference, All Documentation
- Các kênh cộng đồng gồm Discourse, Discord, Slack, Reddit, mailing lists, Mastodon, Twitter, Blog, Wiki, YouTube; ngoài ra còn có tài liệu Team và Contributing
1 bình luận
Các ý kiến trên Hacker News
Rất vui khi thấy Racket lên trang nhất. Từ năm 1982, tôi chủ yếu dùng Common Lisp cho lập trình nghiên cứu, nhưng dạo này lại tìm đến Racket thường xuyên hơn
Cũng có những điểm tôi không thích ở Racket; gần như là mọi thứ, ngoại trừ trình biên dịch, hệ thống quản lý gói, GUI IDE, binding cho Emacs, và việc nó là một ngôn ngữ viết rất vui
Tôi không mấy quan tâm đến hệ sinh thái nghiên cứu ngôn ngữ lập trình, có lẽ đó là phần mà các giáo sư khoa học máy tính dẫn dắt dự án coi trọng nhất. Dù vậy, tôi vẫn mong họ thành công
Vì thế tôi cũng có cảm giác như đang đi nhờ không trả tiền trên dự án Racket. Tôi chỉ tận hưởng những phần nhỏ mình thích, bỏ qua phần còn lại, và hầu như không đóng góp gì. Có lẽ ngoại lệ chỉ là cuốn sách nhỏ về Racket mà tôi đã viết
Những tính năng này thật sự hữu ích và quan trọng. Tôi thích Lisp, nhưng ở nơi làm việc tôi chỉ dùng ngôn ngữ đó khi nó là công cụ phù hợp nhất cho việc cần làm. Nhờ các tính năng này, Racket là Lisp duy nhất mà tôi từng có thể biện minh để sử dụng trong thực tế
Nhờ cộng đồng, công cụ và tài liệu học tập, với cá nhân tôi Racket là ngôn ngữ dễ giới thiệu cho người khác. Tôi cũng đã dùng CL và Clojure khá nhiều và có những điểm thích ở chúng, nhưng mỗi ngôn ngữ đều có nhược điểm lớn nên tôi không giới thiệu cho người khác
Tôi cũng không hợp lắm với phần nghiên cứu của ngôn ngữ hay tính năng
lang, và cũng khá không thích HtDP. Nhưng tôi xem đó chỉ là những dự án tôi không quan tâm được xây trên ngôn ngữ mình thích, chứ không phải nhược điểm của bản thân ngôn ngữ. Vì trong thực tế gần như tôi không phải va chạm với chúngNhư thế này có thể xem là đóng góp rất lớn rồi :)
Bản thân ngôn ngữ có các tính năng metaprogramming, nhưng các ngôn ngữ hiện đại đều có metaprogramming
Trải nghiệm của tôi trong cộng đồng phần lớn là những người nói về các vấn đề thực tế
Vì Racket được dùng trong nghiên cứu ngôn ngữ lập trình hoặc các nghiên cứu khác nên nó được nhắc đến trong các bài báo và bài thuyết trình hội nghị liên quan, nhưng không chi phối các cuộc thảo luận
Ví dụ: https://racket.discourse.group/t/levin-tree-search-with-cont...
Tuy nhiên Clojure có cộng đồng lớn hơn và vững hơn. Đổi lại, vì dùng JVM nên việc thiết lập hơi phiền hơn, và cũng có nhiều điểm tinh tế cần để ý hơn
Racket là một ngôn ngữ rất thực dụng. Nếu nó trông chỉ như một sở thích học thuật kỳ lạ, bạn nên xem Bogdan Popa đang làm gì với Racket: https://defn.io/
Cá nhân tôi dùng Racket khi cần binary có GUI native. Nó cũng khá tốt để parse những thứ như JSON, XML, các định dạng tệp văn bản
Cuốn sách đọc kèm How to Design Programs, https://htdp.org/2023-8-14/Book/index.html cũng hay. Đây không hẳn là sách dạy Racket, mà dùng một vài ngôn ngữ giáo dục được triển khai bằng Racket, nhưng thỉnh thoảng có những ý tưởng đáng để ngẫm lại
Hệ thống macro có thể trông kỳ lạ với người đến từ những nơi như CL, nhưng sau khi quen thì tôi thấy dễ giữ được sự tỉnh táo tương đối khi làm metaprogramming
Còn vài tài liệu hữu ích nữa:
https://www.greghendershott.com/fear-of-macros/
https://beautifulracket.com/
Tôi rất thích ngôn ngữ Racket, nhưng quy trình làm việc bị áp đặt thì khó chấp nhận. Khi viết code bằng Python, tôi viết code trong trình soạn thảo rồi chạy trong shell
Racket có thời gian khởi động quá lâu nên cách đó không hiệu quả lắm. Thay vào đó, người ta nói nên tương tác với một máy ảo chạy dài hạn và REPL
Nhưng như vậy thì code đang làm không bắt đầu từ một trạng thái sạch, mà bắt đầu từ trạng thái mà máy ảo đang có tại thời điểm đó. Với những thứ như Jupyter Notebook thì đây là luồng rất tuyệt, nhưng tôi cho là không phù hợp với các chương trình lớn
Dùng
racket/baselàm#langthay vìracketcũng tạo ra khác biệt lớn. Chi tiết có tại https://docs.racket-lang.org/style/Language_and_Performance....Chuyện không bắt đầu từ “trạng thái sạch” có vẻ giống REPL kiểu Common Lisp hơn là Racket. Trong Racket, khi nạp lại tệp hoặc module, thường phải khởi động lại Racket nên sẽ có môi trường mới. Mọi người phàn nàn về điều đó, nhưng tôi thích cách trạng thái sạch của Racket hơn CL
https://docs.racket-lang.org/drracket/drracket-files.html#(p...
Có lẽ cũng có thể từ chối đề xuất khôi phục
“Khi DrRacket khởi động lần đầu, nó kiểm tra xem có tệp sao lưu nào còn lại không, và nếu có thì đề nghị khôi phục tệp sao lưu”
Khi học tại University of British Columbia, môn nhập môn khoa học máy tính dạy Racket. Tôi nghĩ đó là một ngôn ngữ tuyệt vời, và vì ngay cả những sinh viên đã có kinh nghiệm lập trình trước đó cũng hầu như chưa từng dùng Lisp, nó đưa tất cả về cùng một vạch xuất phát
Các thư viện giúp dễ dàng tạo game đơn giản hoặc trực quan hóa cũng rất ấn tượng
Khi làm trợ giảng, khá nhiều sinh viên lên năm hai vẫn chưa biết viết vòng lặp for, và tụt hậu đáng kể ở các thuật toán cơ bản
Sự appreciation sâu hơn của tôi đối với ngôn ngữ hàm chỉ xuất hiện sau lớp lý thuyết tính toán năm tư
Tôi không biết nên tích hợp tất cả các “ngôn ngữ” này của Racket vào một ứng dụng như thế nào. Tôi thấy các ngôn ngữ như
typed/racket,racket/gui,scribble/base, nhưng không hình dung được nếu muốn tạo ứng dụng GUI bằng code có kiểu đồng thời sinh PDF thì phải làm ra saoTôi đã làm theo các tutorial Racket nhiều lần, nhưng vẫn bối rối không biết ghép các “ngôn ngữ” trông có vẻ không liên quan với nhau như thế nào
Cá nhân tôi có cảm giác mỗi chương của tutorial chỉ giải thích những “ngôn ngữ” không liên quan, và không bao giờ cho thấy chúng hoạt động cùng nhau. Một chương nói về web server nhưng không nói về hệ thống class, chương khác nói về một “ngôn ngữ” khác hỗ trợ class nhưng lại không viết web server trong đó
#langnhư một loại chỉ thị compiler áp dụng trong phạm vi tệp đó. Thực tế còn nhiều hơn thế, nhưng đây là điểm khởi đầu ổn. Nếu muốn thêm kiểu vào ứng dụng, chiến lược tốt là làm từng tệp mộtNgoài dòng
#lang, bạn cũng có thể dùngrequiređể nhập thư viện, nên có thể đặt code GUI và code web server chung trong một tệp.#langcũng không nhất thiết bị giới hạn chỉ một ngôn ngữ mỗi lần; nếu không xung đột thì có thể thêm nhiều thứ vào dòng đó"racket". Nếu rất quan tâm đến kiểu, một phần đáng kể có thể là"typed/racket"Đúng là mọi ngôn ngữ đều chia sẻ một nền tảng chung và có khả năng tương tác ở mức nào đó, nhưng hoàn toàn không có khả năng chương trình sẽ được chia đều thành năm mảnh, mỗi mảnh dùng một ngôn ngữ khác nhau. Tài liệu có lẽ sẽ được viết bằng scribble
Dùng các ngôn ngữ khác nhau có thể đem lại các mô hình lập trình về cơ bản khác nhau, và đó cũng là bối cảnh khiến những phát triển như Typed Racket trở nên khả thi, nhưng nó không nên trở thành rào cản lúc bắt đầu
Tóm lại, cứ dùng Racket là được. Nếu thực sự cảm thấy cần tính năng hoặc phong cách lập trình khác, lúc đó hãy tìm xem đã có ngôn ngữ nào cung cấp chưa. Tất nhiên tất cả chỉ là ý kiến của tôi
Website này, Hacker News, được viết bằng Arc và chạy trên Racket: https://en.wikipedia.org/wiki/Arc_(programming_language)
Vấn đề lớn nhất của Racket không phải là ngôn ngữ hay hệ sinh thái: https://news.ycombinator.com/item?id=27531508
Ngay cả nếu cứ hiểu hoàn toàn theo nghĩa đen từ liên kết đó rằng Felleisen cư xử tệ kiểu Torvalds trong một số tương tác cá nhân cụ thể, thì các công trình của ông ấy, bao gồm How To Design Programs, đã có ảnh hưởng rất tích cực đến cuộc sống của tôi và của những người khác. Vì vậy tôi sẽ không bảo mọi người đừng tận dụng chúng
Trong cộng đồng cũng có những “nerd kỳ quặc” với quan điểm mạnh, nên vì họ hiện diện nổi bật hơn nên có thể càng gây khó chịu hơn. Nhưng cũng như nhiều không gian xã hội không có tiền bạc giữ trật tự, đại loại là vậy thôi
Racket là ngôn ngữ tôi thích nhất. Nó nhanh, thực dụng, có nền tảng vững chắc và mô hình concurrency cũng rất tốt. Nó dựa trên các ý tưởng vay mượn và mở rộng từ Concurrent ML
Hệ thống tài liệu cũng xuất sắc và được tích hợp với hệ sinh thái package, nên phần lớn package có tài liệu chất lượng cao với tham chiếu chéo. Tính tương thích ngược cũng tuyệt vời; tôi thấy tốt hơn nhiều so với Python mà tôi đang dùng trong công việc chính hiện nay
Vì vậy, tôi cảm thấy những người nói Racket quá hàn lâm hoặc không thực dụng có lẽ chưa đào đủ sâu, hoặc trước đây là những sinh viên chỉ từng tiếp xúc với các ngôn ngữ phục vụ giáo dục
Dĩ nhiên nó không hoàn hảo. Cộng đồng nhỏ, mức dùng bộ nhớ mặc định của runtime cao, và nếu muốn xử lý song song thì phải khởi chạy một Racket VM cho mỗi system thread, cùng các vấn đề khác. Dù vậy, những điều này sẽ dần cải thiện theo thời gian
Những thứ tôi đã làm bằng Racket trong vài năm qua: trang thương mại điện tử[1], ứng dụng thông báo native cho macOS/iOS đã lên App Store[2, 3, 4], desktop client đa nền tảng cho Apache Kafka[5, 6, 7],
#langcho Lua[8]. Ngoài ra còn nhiều thứ khác[9][10][11]. Tôi nghĩ chúng khá thực dụng[1]: https://defn.io/2019/08/20/racket-ecommerce/
[2]: https://defn.io/2020/01/02/ann-remember/
[3]: https://defn.io/2024/04/09/ann-remember-for-ios/
[4]: https://github.com/bogdanp/remember
[5]: https://defn.io/2022/11/20/ann-franz/
[6]: https://defn.io/2023/10/15/ann-franz-for-windows/
[7]: https://defn.io/2023/08/10/ann-franz-source-available/
[8]: https://defn.io/2022/11/12/ann-racket-lua/
[9]: https://docs.racket-lang.org/http-easy/index.html
[10]: https://docs.racket-lang.org/deta/index.html
[11]: https://docs.racket-lang.org/gui-easy/index.html
Anh ấy cũng rất tích cực trên diễn đàn cộng đồng và đã đưa ra rất nhiều câu trả lời cực kỳ hữu ích
Tôi nghĩ anh ấy là người hùng thầm lặng của ngôn ngữ này nên nhất định muốn nhắc đến. Có thể nói các thư viện của bạn đang vận hành những đoạn code giúp cuộc sống của những người dùng chẳng biết gì trở nên dễ dàng hơn nhiều :)
https://docs.racket-lang.org/http-easy/index.html
https://docs.racket-lang.org/gui-easy/index.html
https://racket.discourse.group
Có thể là do các lĩnh vực mà Python chủ yếu được dùng ngày nay. Đợt chuyển đổi Numeric/Numpy khoảng năm 2000 thì hoàn toàn khác
Việc bị phá vỡ vài năm một lần có thể chấp nhận được với các startup kỳ lân hoặc các công ty di chuyển nhanh và, theo đúng nghĩa đen, phá vỡ thứ gì đó. Nhưng cũng có rất nhiều chương trình có giá trị đối với những người và tổ chức không có dư nguồn lực để viết lại các thuật toán đã trưởng thành vài năm một lần, hoặc không xem việc đó là ưu tiên
Thỉnh thoảng tôi dùng Racket và thích nó. Tuy nhiên, tôi nhận ra rằng một số Lisp, đặc biệt là Common Lisp và có lẽ cả Guile, cũng đang bị đánh giá thấp hơn so với thực tế
Muốn hỏi những người hiểu rõ hơn: có tính năng nào của Racket ban đầu trông không thực dụng, không liên quan hoặc không hữu ích, nhưng khi dùng rồi lại hữu ích một cách bất ngờ cho việc lập trình không?
Khoảng 20 năm trước, trước khi MzScheme trở thành PLT Scheme, tôi từng làm việc trên phần mềm thương mại về bảo mật email dùng nó làm ngôn ngữ nền tảng. Mã chạy đa nền tảng trên Solaris, Linux, HP-UX, và phần mã riêng cho từng hệ điều hành chỉ khoảng 1.000 dòng C
Các quy tắc lọc được biên dịch thành chính Scheme. Toàn bộ mã, bao gồm cả UI nền web, khoảng 30.000 dòng, và chỉ có 5–6 lập trình viên
Sau này, sau khi di cư, tôi vào một công ty có sản phẩm tương tự nhưng ít tính năng hơn; sản phẩm đó viết bằng C++ với hàng trăm nghìn dòng mã và cũng có nhiều lập trình viên hơn