Cảm nhận sau một tháng sử dụng ngôn ngữ lập trình Clojure
Tác giả chia sẻ trải nghiệm chuyển đổi sang sử dụng Clojure để viết trình tạo trang tĩnh, so sánh ngôn ngữ này với Common Lisp và Scheme. Bài viết nhấn mạnh sự nhất quán, thư viện chuẩn phong phú và cấu trúc dữ liệu linh hoạt của Clojure, dù vẫn còn một số rào cản về cú pháp ban đầu.
Tôi hiện đang sử dụng Clojure để tạo ra trang web này (vâng, ngay sau khi viết lại nó bằng GNU Make và shell; tôi có vấn đề với việc thay đổi công cụ liên tục thôi). Theo một truyền thống cá nhân, tôi đã chọn viết một trình tạo trang tĩnh (static site generator) làm dự án để chơi đùa và học Clojure như một ngôn ngữ mới. Dù trước đây tôi thường chế giễu Clojure vì cú pháp rườm rà của nó (ba loại dấu ngoặc!?), nhưng thực tế nó lại khá tiện dụng và mạnh mẽ.
Dưới đây là những ấn tượng của tôi sau khoảng một tháng làm quen với Clojure.
Những điểm tôi thích
Nhất quán hơn Common Lisp
Common Lisp được gọi như vậy vì nó là sự thỏa hiệp giữa hầu hết các phương ngữ Lisp tồn tại vào thời điểm đầu những năm 80. Do đó, nó là một sự pha trộn kỳ lạ giữa các mô hình lập trình và quy tắc đặt tên. Ví dụ, thay vì map một hàm qua một danh sách, bạn lại dùng mapcar. Thay vì filter, bạn lại viết remove-if-not, gây ra sự nhầm lẫn kiểu phủ định kép. Nhìn chung, Common Lisp mang cảm giác mạnh mẽ là được thiết kế bởi một ủy ban, điều này hoàn toàn hợp lý vì thực tế nó là như vậy.
Vì Clojure mới hơn và là đứa con tinh thần của một người, nên nó nhất quán hơn như một ngôn ngữ. Ví dụ, sự trừu tượng hóa seq có nghĩa là tôi thường không phải lo lắng về loại chuỗi mình đang xử lý. Thay vì phải nhớ aref cho mảng và nth cho danh sách, tôi chỉ cần dùng nth cho mọi thứ.
Nó cũng làm việc ánh xạ (mapping) dễ dàng hơn: thay vì phải nhớ các vòng lặp phức tạp hay maphash, tôi có thể đơn giản gọi (map (fn [[k v] ...]) hash-table) và xong việc. Và hãy nhớ rằng, map hoạt động với mọi tập hợp. Tương tự với sự bình đẳng: thay vì phải nhớ sự khác biệt tinh tế giữa eq, eql, equal, equalp và nhiều cái khác phụ thuộc vào kiểu dữ liệu, tôi chỉ cần gọi = (hoặc == nếu so sánh giá trị số, hoặc identical? để xem giá trị có giống hệt nhau không). Công bằng mà nói, vẫn có những lưu ý, nhưng tôi chưa gặp phải chúng trong một tháng qua. Với Lisp, tôi phải học các hình thức bình đẳng khác nhau ngay lập tức mới có thể bắt đầu.
"Đầy đủ tính năng" hơn Scheme
Scheme cũng được xây dựng bởi một ủy ban, nhưng bạn có thể lập luận rằng nó thậm chí còn nhất quán hơn Clojure. Tuy nhiên, sự nhất quán của nó giống như một chiếc xe đạp: nó rất ít tính năng tiện dụng, cắt giảm ngôn ngữ xuống những xương tủy cơ bản nhất. Thật vậy, phần giới thiệu cho mọi bản sửa đổi của Báo cáo Scheme đều bắt đầu bằng: "Ngôn ngữ lập trình nên được thiết kế không bằng cách xếp chồng tính năng lên tính năng, mà bằng cách loại bỏ những điểm yếu và hạn chế khiến các tính năng bổ sung trở nên cần thiết."
Những người dùng Scheme thường khoe rằng đặc tả R5RS vừa vặn trong 50 trang, điều này ấn tượng, nhưng các chức năng cơ bản như xử lý lỗi, xử lý tệp và thậm chí cả hash-maps đều bị thiếu trong ngôn ngữ cốt lõi. Trong khi R6RS thêm nhiều chức năng, nó cũng gây ra sự chia rẽ lớn trong cộng đồng mà R7RS đang cố gắng hàn gắn, nhưng tiến độ chậm. Scheme giống như một viên ngọc quý, sự hiện thực hóa của một lý tưởng lập trình thuần túy.
Clojure, mặt khác, thực dụng: nó có một thư viện chuẩn lớn và chạy trên JVM, vì vậy có lẽ có một thư viện cho bất kỳ lĩnh vực nào bạn đang làm việc. Đặc biệt là với tư cách là một lập trình viên nghiệp dư, tôi rất trân trọng hệ sinh thái này.
Cấu trúc dữ liệu tiện dụng
Một trong những điều đầu tiên thu hút tôi đến Lisp là nó là một ngôn ngữ "mọi thứ là...". Bạn biết đấy, giống như Lua: mọi thứ là bảng (table); Tcl: mọi thứ là chuỗi (string); Lisp: mọi thứ là danh sách (list). Tôi chỉ yêu những ngôn ngữ nơi có một Ý tưởng Lớn và nó được thực hiện triệt để.
Tuy nhiên, trong "đời thực", không phải mọi thứ đều là danh sách. Có, ví dụ, các vector (danh sách truy cập ngẫu nhiên), hoặc từ điển (danh sách liên kết). Các ngôn ngữ Lisp khác ngoài Clojure cũng có những thứ này, nhưng Clojure khiến chúng trở thành hạng nhất và tiện dụng. Đây là điều về Clojure mà tôi mất nhiều thời gian nhất để thích, vì tôi thực sự thích tính chất "mọi thứ là danh sách" của Lisp. Nhưng bốn kiểu dữ liệu cơ bản của Clojure—danh sách (tuyệt vời!), vector, hash-map và set—được lựa chọn tốt và được đối xử bình đẳng bởi ngôn ngữ cốt lõi, điều này là chìa khóa cho sự tiện dụng của chúng.
Những điểm vấp ngã
Không có ngôn ngữ lập trình nào là hoàn hảo, và tất nhiên có một số điểm đau đầu mà tôi tìm thấy ở Clojure cho đến nay.
Quá nhiều cú pháp
Tôi hứa là tôi không đùa về điều này. Một điều tôi thực sự thích về Lisp là tính đồng nhất của cú pháp: nó toàn là dấu ngoặc đơn và khoảng trắng. Ngôn ngữ duy nhất có ít cú pháp hơn là Forth, theo tôi biết. Mặc dù là một Lisp (đừng ném đá tôi), Clojure có nhiều cú pháp hơn nhiều so với, ví dụ, Scheme. Có (), [], {}, và #{} cho các chuỗi; . và / trong tên ký hiệu có ý nghĩa đặc biệt; và một điều thực sự khiến tôi nản trong một thời gian là cú pháp unquote ~. Tôi thực sự thích sự đối xứng của ` và ,!
Tuy nhiên, tôi thừa nhận rằng theo thời gian tôi đã quen với cú pháp và thậm chí còn trân trọng nó bây giờ (xem ở trên). Tôi chỉ ước có một cách dễ dàng hơn để di chuyển qua đống ]}}))) ở cuối các khối mã.
Tôi không biết Java
Clojure nhấn mạnh việc là một ngôn ngữ được lưu trữ (hosted language), tức là ngôn ngữ chạy trên một thời gian chạy (runtime) có sẵn. Với Clojure gốc, runtime đó là JVM, mà theo mọi tài khoản thì là một runtime tốt và nhanh. Tuy nhiên, tôi không biết chút nào về Java, ngoại trừ việc nó được cho là dài dòng. Trong những tuần đầu tiên sử dụng Clojure, tôi chưa thực sự cần phải học Java, nhưng cảm giác rằng tôi nên học nó vẫn còn đó. Ít nhất thì tôi đã (hầu hết) tìm ra quy ước gọi interop.
Tôi sẽ gắn bó với Clojure thêm một thời gian nữa
Tất cả những điều trên được nói ra, tôi sẽ gắn bó với Clojure trong thời gian tới. Nó thú vị, khá dễ sử dụng, và với các dự án như babashka, nó nhanh chóng và thuận lợi cho việc viết script. Hơn nữa, tôi nghĩ rằng việc làm quen hơn với hệ sinh thái Java chưa bao giờ là một ý tưởng tồi.
Để có thêm kinh nghiệm ngoài việc viết hệ thống xây dựng trang web, tôi đang giải các bài toán Project Euler bằng Clojure.



