1 điểm bởi GN⁺ 2023-08-09 | 1 bình luận | Chia sẻ qua WhatsApp
  • Raku từng được xem xét như một ứng viên ngôn ngữ máy tính bỏ túi để lấp khoảng trống trong các tác vụ toán học của Python, J, Frink và Excel; chỉ qua một thử nghiệm ngắn cũng đã tạo ấn tượng là một ngôn ngữ rất mạnh nhưng kỳ quặc
  • Có phạm vi sức biểu đạt xoay quanh toán tử rất rộng, như ký hiệu Unicode, toán tử trung tố gồm chữ và số, tích danh sách・zip・reduce・tích lũy, matcher ~~, chuỗi ...
  • Người dùng không chỉ có thể định nghĩa toán tử trung tố mà còn cả toán tử circumfix/postcircumfix, và cũng có thể chỉ định tính kết hợp vượt ra ngoài kết hợp trái・phải, gồm kết hợp dạng chuỗi và dạng danh sách
  • Đa điều phối không chỉ rẽ nhánh theo chữ ký kiểu mà còn theo vị từ runtime where; chữ ký hàm và cả các tham số bên trong chữ ký cũng có thể được xử lý như giá trị hạng nhất
  • Việc bảo trì codebase lớn có vẻ sẽ là gánh nặng, nhưng Raku hấp dẫn với lập trình quy mô nhỏ như script dùng một lần, tính toán, công cụ cá nhân; tài liệu, REPL trên Windows, tốc độ biên dịch và lỗi sigil là các trở ngại chính

Cơ duyên tìm hiểu Raku và ấn tượng đầu tiên

  • Raku là ngôn ngữ trước đây được biết đến với tên Perl 6
  • Sau khi viết về những bất mãn với ngôn ngữ động, một số người dùng đã gợi ý Raku, nên tôi tìm hiểu để xem nó có phù hợp làm ngôn ngữ máy tính bỏ túi cho các tác vụ toán học hay không
  • Trước đó tôi dùng kết hợp Python, J, Frink, Excel, nhưng mỗi thứ đều có nhược điểm lớn
  • Sau vài ngày thử nghiệm, ấn tượng nhận được gần giống như “một ngôn ngữ được thiết kế bởi những gremlin thật sự thông minh, sau khi thu thập rất nhiều phản hồi từ các gremlin khác”

Hệ thống toán tử khác thường

  • Raku tích cực sử dụng toán tử Unicode
    • Kiểm tra một phần tử có thuộc tập hợp hay không bằng
    • Cũng có , ,
  • Cũng cho phép toán tử trung tố gồm chữ và số
    • Toán tử lặp chuỗi là x
    • Hợp thành hàm là o
  • Tổ hợp danh sách cũng được biểu diễn bằng ký hiệu ngắn
    • X tạo tích Descartes của danh sách
    • Xf áp dụng f cho từng phần tử của tích Descartes
    • Zf làm việc tương tự theo kiểu zip
  • Với toán tử trung tố f, [f] reduce một danh sách, còn [\f] tạo kết quả tích lũy
    • [+] <1 2 3 4 5>15
    • [\+] <1 2 3 4 5>(1 3 6 10 15)

Matcher ~~ và chuỗi ...

  • ~~ được dùng như một matcher xử lý nhiều kiểu so sánh bằng cùng một cú pháp
    • "abc" ~~ "abc" kiểm tra chuỗi có khớp hay không
    • "abc" ~~ Str kiểm tra có phải kiểu chuỗi hay không
    • "abc" ~~ {.chars == 3} kiểm tra độ dài có bằng 3 hay không
    • "abc" ~~ /^b/ kiểm tra abc có bắt đầu bằng b hay không
  • ... nắm bắt mẫu từ các giá trị phía trước để tạo chuỗi
    • 0,1,2...10 tăng từng bước 1 từ 0 đến 10
    • 0,2,4...10 trở thành chuỗi số chẵn
    • 1,2,4...10 đi theo mẫu tăng như 1 2 4 8

Toán tử do người dùng định nghĩa

  • Raku không chỉ dừng ở việc định nghĩa toán tử trung tố như một số ngôn ngữ, mà còn có thể tạo toán tử circumfixpostcircumfix
  • Ví dụ, có thể định nghĩa một toán tử bao quanh như sub circumfix:<[∀ zz>($inner){sum($inner)} để cộng các giá trị bên trong
  • Cũng có thể định nghĩa toán tử postcircumfix trông giống tích vô hướng vector
    • sub postcircumfix:<| ⟩>(@left, @inside){[+] (@left Z* @inside)}
    • <1 2 3>|<4 5 6>⟩32
  • Tính kết hợp của toán tử cũng có thể được chỉ định theo nhiều cách
    • Có thể định nghĩa toán tử trung tố kết hợp trái・kết hợp phải thông thường
    • Có thể chỉ định kết hợp dạng chuỗi, trong đó x < y < z được diễn giải như x < y && y < z
    • Cũng hỗ trợ kết hợp dạng danh sách, trong đó a op b op c trở thành op(a, b, c)

Đa điều phối và rẽ nhánh theo điều kiện runtime

  • Raku hỗ trợ đa điều phối, chọn định nghĩa phù hợp trong số nhiều định nghĩa hàm có chữ ký kiểu khác nhau
  • Hàm ví dụ f hoạt động khác nhau tùy theo tổ hợp đối số
    • Nếu nhận một scalar và một mảng, nó cộng scalar vào từng phần tử của mảng
    • Cũng hỗ trợ trường hợp nhận mảng và scalar
    • Nếu nhận hai mảng, nó cộng từng phần tử bằng Z+
  • Điểm đặc biệt hơn là cũng có thể điều phối theo vị từ runtime của giá trị
    • multi my_abs(Int $x where {$x > 0}) {$x}
    • multi my_abs(Int $x) {-$x}
  • Chữ ký của hàm là giá trị hạng nhất, và các tham số bên trong chữ ký cũng là giá trị hạng nhất

Bề mặt rộng được tạo nên từ những tính năng nhỏ

  • Nếu định nghĩa hàm MAIN, các tham số của nó sẽ tự động được chuyển thành cờ CLI
  • Đối tượng có rất nhiều phương thức được cung cấp sẵn
    • Đối tượng List cung cấp các phương thức để lấy mọi hoán vị, mọi tổ hợp k phần tử, và mọi cửa sổ trượt
  • Junctions là một dạng giá trị đặc biệt để thực hiện nhiều so sánh cùng lúc
    • 1|2 được mở rộng thành any(1, 2), nên 1 < 1|2 đúng
    • 1&2 được mở rộng thành all(1, 2), nên 1 !< 1&2 đúng
  • Bất kỳ toán tử trung tố nào cũng có thể trở thành toán tử phủ định bằng cách thêm ! phía trước
  • Raku có vẻ là một ngôn ngữ vừa có tên dạng $kebab-case vừa có phép trừ trung tố, và có lẽ sigil giúp phân biệt x-y
  • Cú pháp regex không tương thích ngược với Perl 5
    • Trong 30 năm, các ngôn ngữ đã đi theo “chuẩn” PCRE, nhưng Perl 6 đã bỏ nó

Những phần chưa xem xét và sức hấp dẫn ở quy mô nhỏ

  • Những gì đã xem chỉ là một phần tính năng xoay quanh mục đích dùng như máy tính bỏ túi
  • Tôi vẫn chưa học hệ thống đối tượng, package, grammars
  • Cũng còn nhiều tính năng bị bỏ sót, như samewith trong thân hàm gọi lại cùng hàm đó với đối số mới
  • Nếu phải bảo trì một codebase Raku legacy thì có lẽ sẽ rất vất vả, nhưng Raku trông mạnh mẽ cho kiểu lập trình In The Small
    • Script dùng một lần
    • Tính toán
    • Công cụ cá nhân
    • Loại công việc ban đầu tôi mong muốn

Bất mãn và kỳ vọng

  • Tài liệu rất thiếu, và do phụ thuộc nhiều vào ký hiệu nên khó tìm kiếm
    • Dù đã có kinh nghiệm học nhiều ngôn ngữ thiếu tài liệu, Raku còn lớn và phức tạp hơn nhiều, nên có thể làm giảm động lực
  • Trên Windows, nhập Unicode vào REPL sẽ gây crash
  • Trình biên dịch cũng khá chậm, ngay cả file nhỏ cũng mất hơn 0,5 giây, khiến các tác vụ lặp đi lặp lại trở nên khó chịu
  • Hệ thống sigil gây bất tiện
    • Có trường hợp mất 30 phút debug chỉ vì dùng $x thay cho @x
  • Nhìn chung tôi thích Raku và mong nó thành công, nhưng hy vọng theo thời gian thời gian biên dịch và tài liệu sẽ được cải thiện

1 bình luận

 
GN⁺ 2023-08-09
Ý kiến trên Hacker News
  • Nếu đặt các ngôn ngữ lập trình lên một không gian hai chiều, các trục có thể là mức độ khiến ta ngạc nhiên và, khi đã ngạc nhiên, liệu điều đó thú vị hay kinh khủng
    Với các ngôn ngữ bình thường, người ta thường ngầm kỳ vọng chúng nằm ở góc dưới bên trái: “hầu như không gây ngạc nhiên, nhưng nếu thỉnh thoảng có thì cũng là ngạc nhiên thú vị”. Còn Raku thì có cảm giác công khai nhắm tới góc trên bên trái vốn hiếm khi có ai đứng vào. Gần như là thái độ “Lạ nhỉ? Không phải rất hay sao?”

    • Vấn đề là các trục đó mang tính chủ quan. Có thứ vừa thú vị vừa kinh khủng; trước đây tôi từng viết JavaScript kiểu document.write = function ..., và xét ở chỗ nó làm được việc cần làm thì khá thú vị, nhưng đồng thời cũng khá kinh khủng
    • Khi phải làm parser cho bài tập đại học, tôi biết đến tính năng grammar của Raku; nó làm thay gần như mọi thứ nên có cảm giác như dùng mã gian lận, nhưng vẫn rất vui
    • Dù sao ban đầu nó là Perl 6, nên cũng không ngạc nhiên khi các lập trình viên Perl muốn một ngôn ngữ chẳng giống ngôn ngữ nào khác
      Perl cũng có nhiều “bất ngờ thú vị”, và tôi nghĩ Raku chủ yếu được thiết kế để loại bỏ những bất ngờ kinh khủng của Perl
    • Đến đoạn dùng để kiểm tra một phần tử có thuộc tập hợp hay không thì tôi hiểu ý rồi
      0,2,4...10 trở thành (0 2 4 6 8 10), nhưng việc 1,2,4...10 thành (1 2 4 8) lại khiến tôi tự hỏi “nó đang tìm số tiếp theo trên OEIS à?”
    • Càng đọc sang các đoạn sau, Raku càng có vẻ đi dần về góc trên bên phải, tức vùng vừa gây ngạc nhiên vừa kinh khủng
  • Raku là một ngôn ngữ thú vị, nhưng một số idiom của nó không dễ đi vào đầu
    Giống như AppleScript từng cố trông giống ngôn ngữ tự nhiên nhưng lại tạo cảm giác kỳ quặc, Raku pha trộn các yếu tố mang hơi hướng ngôn ngữ tự nhiên như my, say, sub, gather với các ký hiệu như @, khai báo module và những quyết định cú pháp mà với người ngoài trông khá Byzantine. Ví dụ 99 bottles về mặt logic thì vẫn lần theo được, nhưng khó mà tự trực giác phát hiện ra. Cảm giác có nhiều ký hiệu và chúng bị quá tải tùy theo ngữ cảnh, nên ngay cả với những việc mà Raku có thể tối ưu, như parser ngôn ngữ tự nhiên, tôi cũng không muốn trực tiếp dùng nó
    https://examples.raku.org/categories/module-management/Fletc...

    • Có vẻ bạn chưa từng dùng Perl. Nếu có nền tảng Perl thì khá nhiều cú pháp đó, đặc biệt sigil @ biểu thị mảng, sẽ trông rất quen
    • Tôi cũng có cảm giác y như vậy khi nhìn Bash
  • Tính năng tôi thích nhất ở Raku là phép chia số nguyên và các literal thập phân đều trả về Rat, một kiểu số hữu tỉ
    Ai cũng biết số thực dấu phẩy động không hay lắm, nhưng rất ít ngôn ngữ thực sự cố thoát khỏi nó; trong Raku, phải dùng ký pháp khoa học thì literal mới là số thực dấu phẩy động

    • Những ngôn ngữ lâu đời hơn như Common LispScheme cũng đang chờ được những người ghét số thực dấu phẩy động IEEE 754 chú ý
      Chúng có một hệ phân cấp số bao gồm cả số hữu tỉ và số hữu tỉ phức, và dĩ nhiên cũng hỗ trợ số có độ chính xác tùy ý. Khả năng kết hợp rất tuyệt
    • Thực ra đây gần như là một tính năng tệ. Vì khi biểu diễn Rat trở nên quá lớn, nó sẽ tự động chuyển sang số thực dấu phẩy động
      1/10Rat, nhưng 1/100000000000000000000 lại là Num. Cũng có FatRat không bị nâng cấp như vậy, nhưng đó không phải mặc định
    • Hệ phân cấp số của Scheme đã xử lý đúng các biểu diễn chính xác suốt nhiều thập kỷ
      Vì vậy, thay vì nói rằng “nó đã thoát khỏi cách dùng số thực dấu phẩy động không chính xác dù ta không yêu cầu rõ ràng”, đúng hơn là ngay từ đầu nó chưa từng ở trong tình trạng đó
    • Racket cũng sẽ nói khác. Nó hoạt động đúng
      (/ 1.0 3.0)0.3333333333333333, (/ 1 3)1/3, và (- (+ 0.1 0.2) 0.3)5.551115123125783e-17
    • Tôi không chắc điều này có tốt không. Tôi biết khi nào nên dùng kiểu thập phân/hữu tỉ và khi nào nên dùng số thực dấu phẩy động, nhưng trong mã Python cá nhân của tôi, số lần gọi float() nhiều hơn Decimal() rất nhiều
      Nếu không trực tiếp xử lý tiền bạc thì hầu như lúc nào số thực dấu phẩy động cũng là lựa chọn mong muốn
  • Tôi không thấy tài liệu Raku “thật sự tệ”; ngược lại, trang tài liệu chính thức gây ấn tượng vì là nguồn một cửa chứa cả tài liệu khái niệm lẫn tài liệu API
    https://docs.raku.org/
    Trang này là điểm khởi đầu rất tốt cho tài liệu khái niệm: https://docs.raku.org/language

    • Tôi đã dùng Raku vài năm, và tài liệu vừa rất tốt nhưng cũng còn thiếu
      Phần lớn nội dung hiện có được viết tốt và có các ví dụ mã hữu ích, nhưng thỉnh thoảng tôi gặp những phần hoàn toàn chưa được ghi tài liệu hoặc chỉ xử lý các trường hợp đơn giản. Đặc biệt hệ thống module là vấn đề lớn nhất, và chỉ đọc trang Modules thì khó hiểu được sự khác nhau giữa module/package. Namespace được import và namespace được khai báo có thể khác nhau, nhưng để compiler tìm thấy thì cấu trúc thư mục phải khớp với namespace; điều này hữu ích và kỳ lạ là cũng có lý, nhưng tôi đã phải tự mò qua thực hành mới học được
    • Đó là do văn hóa Perl. FAQ và các trang manual của Perl từng ở đẳng cấp hàng đầu nhờ tính cách của những lập trình viên dùng Perl: dí dỏm, súc tích và kỳ quặc
    • Các trang manual của Perl lúc nào cũng xuất sắc
  • Các toán tử Unicode đẹp mắt của Raku đều có cách viết thay thế bằng ASCII
    Ví dụ cách viết thay thế cho , , , lần lượt là (elem), !(elem), (cont), !(cont)
    https://docs.raku.org/language/unicode_ascii#Other_acceptabl...

    • Nếu là tôi thì chắc chắn sẽ dùng phiên bản ASCII
  • Có vẻ những chỉ trích điển hình xuất hiện trước khi người ta hiểu rõ ngôn ngữ vẫn đang được lặp lại. Trước đây là “nhiễu dòng” của Perl, còn giờ là kiểu nói Raku không ngại dùng toán tử Unicode
    Nhưng đó là tùy chọn, và tôi đã tự thử dùng để làm cho mã trên màn hình trông gọn và giàu biểu đạt hơn. Nó rất hợp với việc dùng Unicode một cách thận trọng và sáng tạo. Phản ứng ghét sigil cũng khá phổ biến, nhưng vì thích khả năng biểu đạt kiểu “cưa máy đa năng Thụy Sĩ” của Perl nên tôi đã dùng Raku/Perl 6, và Raku có cảm giác như Perl được nâng lên bình phương theo đúng chất Perl. Nó gọn gàng, giàu biểu đạt, và là một đống tính năng khổng lồ chồng lên Perl cổ điển tốt đẹp. Tài liệu cũng tốt, nhưng vẫn cần được chăm chút liên tục; nếu so với tài liệu Perl thì tiêu chuẩn rất cao

    • Tôi thắc mắc toán tử phi ASCII được nhập như thế nào. Không rõ là dùng layout bàn phím đặc biệt, trình soạn thảo tự động chuyển đổi một chuỗi nào đó, hay dùng escape Unicode thô
      Làm vậy chỉ để tiết kiệm vài ký tự thì có vẻ phức tạp và không có nhiều ý nghĩa
  • Thỉnh thoảng tôi từng tự hỏi một ngôn ngữ lập trình đầy cú pháp đường sẽ trông như thế nào, giờ thì biết rồi
    Cảm giác kiểu “kinh khủng mà lạ lùng cuốn hút, không thể rời mắt, cho xem thêm nữa đi”

    • Có thể bạn sẽ thích noulith, một ngôn ngữ sở thích do người từng thắng nhiều kỳ Advent of Code gần đây tạo ra
      Phần giới thiệu trên GitHub viết: “slaps roof of [programming language]* this bad boy can fit so much [syntax sugar] into it.” Người đó cũng dùng ngôn ngữ này để thắng kỳ Advent of Code gần nhất: https://github.com/betaveros/noulith
    • Cứ chờ đến khi biết đến Grammars của Raku xem
    • Mỗi lần nhìn C++ hiện đại tôi cũng có phản ứng tương tự
  • Cũng đáng nhớ rằng Raku ban đầu bắt đầu với tên Perl 6, và nhiều triết lý thiết kế xuất phát từ tư duy kiểu Perl
    Nhìn phản ứng ngay với toán tử x dùng để lặp chuỗi, có vẻ tác giả không rành lịch sử của Perl và Raku lắm; chuyện đó đã tồn tại trong Perl suốt nhiều thập kỷ rồi

    • Trong bài có câu “cú pháp regex không tương thích ngược với Perl 5. Suốt 30 năm các ngôn ngữ đã đi theo ‘chuẩn’ PCRE, vậy mà Perl 6 cứ thế vứt bỏ hết”, nên ít nhất tác giả có vẻ biết ở mức nào đó
    • Chú thích đầu tiên có nói Raku trước đây được biết đến là Perl 6
    • Câu “Perl6/Raku hoàn toàn khác Perl 5” bị phóng đại quá mức
      Không phải tự nhiên nó được gọi là Perl 6, và gần như cùng một đội Perl đã phát triển nó. Ai từng dùng Perl 5 kha khá sẽ thấy rõ di sản trong Perl6/Raku. Toàn bộ mô hình đối tượng của Raku cũng gần như là một phiên bản mạnh hơn một chút của Moose.pm, module Perl 5 trên CPAN
  • Thành thật mà nói, cú pháp regex Perl 5/PCRE thật kinh khủng
    Lý do nó tồn tại chỉ là vì trong cú pháp regex cũ, (? từng là lỗi cú pháp, nên có thể tái định nghĩa thành bất cứ thứ gì. Raku là nỗ lực thiết kế một ngôn ngữ regex lành mạnh ngay từ đầu, khi ta đã biết regex cần biểu đạt điều gì. Phương án thay thế là bị mắc kẹt thêm 30 năm nữa với những thứ như (?:this|(?>or that))

    • Không hẳn là kinh khủng, mà là hắc thuật không thể giải mã; hiểu rồi thì thấy hay
      Đã lâu không đụng đến Perl, nhưng tôi vẫn thường xuyên dùng regex
    • Đồng ý, nhưng nó thực sự hữu ích
  • Theo một nghĩa nào đó thì đúng là gremlin. Tôi thích những công cụ kỳ quặc, phức tạp nhưng giúp tăng năng suất
    Tuy nhiên tôi không đồng ý với so sánh “chương trình lớn vs chương trình nhỏ”. Người kém khôn ngoan hơn có thể hiểu đó là ngôn ngữ tệ cho các công việc lớn, nhưng thực tế nó có thể tốt ngang hoặc tốt hơn các ngôn ngữ khác. Vấn đề là, cũng như các ngôn ngữ gremlin khác, muốn dùng tốt thì cần sự khôn ngoan. Ví dụ, người nhầm $x với @x gần như không có nếu họ đã dùng đủ nhiều ngôn ngữ tương tự. Sigil khi đọc mã sẽ cho biết ngay kiểu đơn giản của biến, trong Raku là interface, nên lại tiện hơn; cùng một không gian tên biến cũng có thể được dùng hữu ích với các sigil khác nhau. Nó trông kỳ lạ, có vẻ là ký tự thừa và cần biết ý nghĩa, nhưng có thể làm cuộc sống dễ hơn: https://www.perl.com/article/on-sigils/
    Vấn đề nảy sinh với những người không thật sự biết mình đang làm gì. Với họ, ngôn ngữ gremlin này có thể là cơn ác mộng sống, và họ cần rất nhiều thiết bị bảo hộ như bumper bowling, phao bơi, găng Kevlar, mũ bảo hộ, GPS. Điều đó không có nghĩa là không thể xây nhà chọc trời bằng ngôn ngữ gremlin; chỉ là những non-gremlin dễ gây tai nạn thì không xây được, còn gremlin khôn ngoan thì có thể

    • Tôi cho rằng lối nghĩ “công cụ này chỉ dành cho người đủ giỏi” là một mùi thiết kế rất lớn
      Công cụ tồn tại để giúp đội ngũ làm tốt hơn hoặc nhanh hơn những việc họ cần làm. Nếu dùng một công cụ phức tạp không cần thiết để sàng lọc junior hoặc thỏa mãn cái tôi, thì công cụ đó với phần còn lại của tổ chức gần giống một vũ khí hơn là sự trợ giúp