Cognition: ngôn ngữ antisyntax mới đang định nghĩa lại metaprogramming
(ret2pop.nullring.xyz)- Cognition là một dự án nghiên cứu ngôn ngữ chọn antisyntax hậu tố hoàn toàn (postfix) để tránh vấn đề đọc trước (read-ahead) của Lisp và các ngôn ngữ concatenative
- Các cơ chế cốt lõi là delimiter, ignore, singlet, falias, crank, metacrank cho phép chương trình tự thay đổi quy tắc token hóa và chu kỳ thực thi của chính nó
- Bootstrap bắt đầu từ trạng thái mọi ký tự đều được đọc như một token đơn lẻ, rồi tự chuyển sang môi trường dùng khoảng trắng và xuống dòng làm delimiter
crankvàmetacrankkiểm soát khi nào token được đánh giá và khi nào chỉ được chất đống lại, nhờ đó định nghĩa được cú pháp prefix như chú thích#, escape\\, quote[, macro(bên trong một hệ thống hậu tố- Ngay cả một phương ngữ Brainfuck cũng được hiện thực bằng các từ Cognition và quy tắc token hóa thay vì parser riêng, cho thấy hướng biến chính cú pháp thành mã và tự động hóa nó
Những điểm Cognition xem là vấn đề trong cú pháp hiện có
- Lisp cung cấp metaprogramming mạnh nhờ s-expression và hệ macro, nhưng vẫn chịu ảnh hưởng của cú pháp cố định
- Dấu ngoặc trái là tín hiệu phải đọc cho đến khi gặp ngoặc phải, nên rất khó hoặc trong một số triển khai là không thể thay đổi vai trò của ngoặc từ bên trong ngôn ngữ
- Nếu muốn thay đổi cách phân tách các token đã đọc rồi ở thời điểm sau thì cần rất nhiều xử lý chuỗi
- Quá trình nhìn vào đầu vào hiện tại rồi phải đọc thêm phía sau chính là syntax; một khi đã giả định đọc trước ở mức cơ bản thì sẽ bị ràng buộc vào một số dạng cú pháp nhất định
- Cognition dùng antisyntax hậu tố hoàn toàn để tránh điều này
- Nó giống các ngôn ngữ concatenative, nhưng tác giả cho rằng ngay cả các ngôn ngữ concatenative thông thường cũng gặp vấn đề đọc trước do dấu ngoặc vuông hoặc ký tự quote chuỗi
- Hệ macro của Racket được xem là khác biệt vì nó dùng tiền xử lý chứ không phải thay đổi cú pháp động khi chạy
Dự án và ý tưởng cơ bản
- Cognition là một dự án nghiên cứu đang hoạt động được thực hiện trong vài tháng cùng Matthew Hinton
- Kho mã triển khai nằm tại cognition-rust, và kho này cũng có bài báo về ngôn ngữ
- Việc hiểu parsing, tokenization và cú pháp sẽ giúp theo dõi dễ hơn
- Phần giải thích bắt đầu từ mã “baremetal cognition” rồi phát triển dần theo hướng cú pháp tương tự Stem
Baremetal Cognition và token hóa
- Nhìn bề ngoài, baremetal Cognition khá giống Brainfuck, nhưng có khả năng metaprogramming mạnh hơn
- Mã bootstrap rất nhỏ dùng cả khoảng trắng và xuống dòng như những ký hiệu có ý nghĩa, và ở trạng thái ban đầu mọi ký tự đơn đều được đọc thành token
- Cognition về cơ bản là thiết kế dựa trên stack, nhưng dùng thuật ngữ container theo nghĩa tổng quát hơn stack
- Trong môi trường mặc định, ngoài falias đặc biệt ra thì không có từ nào tự động được thực thi
-
delimiter, ignore, singlet
- delimiter cho tokenizer biết đâu là cuối một token và đâu là đầu token tiếp theo
- Danh sách delimiter ký tự đơn có thể được sửa và đọc ngay trong mã Cognition
- Ký tự ignore bị bỏ qua ở giai đoạn bắt đầu thu thập token của mỗi vòng read-eval-print loop
- Mặc định là mọi ký tự đều là delimiter và không có ký tự ignore nào
- Các danh sách delimiter, singlet, ignore có thể đổi cách hoạt động bằng cờ whitelist/blacklist
- Cấu hình mặc định là blacklist delimiter rỗng, không có singlet được whitelist và không có ký tự ignore nào được whitelist
- singlet là nhóm token hóa thứ ba: nó tự chèn chính nó vào token rồi kết thúc việc thu thập token
-
falias
- falias là danh sách các từ được thực thi ngay khi được đưa lên container
flà falias mặc định; nó không được đẩy vào container mà sẽ thực thi từ ở đỉnh container- Trong ví dụ, khi
fthực thid, thìdsẽ đổi danh sách delimiter thành giá trị chuỗi của từ đó - Sau đó bootstrap tiếp tục bằng cách từng bước biến các ký tự như
l,g,t,dthành non-delimiter, rồi đổi khoảng trắng và xuống dòng thành delimiter và ignore
Môi trường thực thi do bootstrap tạo ra
- Bootstrap ban đầu thay đổi quy tắc delimiter và ignore để cuối cùng tạo ra môi trường trong đó khoảng trắng và xuống dòng là delimiter token, và chúng bị bỏ qua ở bước bắt đầu token
- Sau đó nó đọc
1vàcrank, rồifthực thicrankđể đi vào môi trường crank 1 - Cốt lõi của quá trình này là có thể thay đổi cách token hóa ngay trong lúc chạy
- Việc thay đổi delimiter, singlet, ignore có thể được tự động hóa bằng chương trình
- Vì là hậu tố và không có đọc trước, không cần parse sẵn một hay nhiều token trước khi đánh giá biểu thức
- falias cho phép thực thi một số từ nhất định mà không cần từ prefix hay cơ chế tự thực thi từ cơ bản
crank và metacrank
- crank là cơ chế quyết định token trên stack sẽ được thực thi theo chu kỳ nào
- Từ
cranknhận một số làm tham số, rồi cứ mỗi từ thứntiếp theo được đưa vào container thì sẽ thực thi phần tử trên đỉnh stack1 crankở cuối bootstrap tạo ra môi trường đánh giá mọi token- Ở trạng thái
5 crank, các từ có thể được tích lại cho đến khi token thứ năm đi vào
- Mã ví dụ dùng
unglue,swap,quote,prepose,defđể tạo một từ tên là2crankungluelấy ra giá trị của từ, kể cả function pointer của builtin nhưcrankpreposegiốngcomposecủa Stem nhưng gắn ở phía trước và đưa vào VMACROdefđịnh nghĩa để2crankđặt2lên stack rồi gọi builtincrank
-
Container và macro trong Cognition
- Trong Stem có thể đặt từ trực tiếp lên stack, còn trong Cognition các từ chưa được đánh giá nằm trong container
- Nhờ thiết kế này, các từ như
composecó thể xử lý nhất quán giữa container chứa một từ đơn lẻ và các container khác thông qua cùng một API - Macro của Cognition khác với quote của Stem
- Khi macro được đánh giá, nó bỏ qua crank và mọi phần tử bên trong đều được đánh giá
- Nếu đánh giá một macro được bind vào từ, toàn bộ macro sẽ chạy không phụ thuộc crank, còn cranker chỉ tăng một lần
- Macro hữu ích cho mã độc lập với crank và cho các expansion phục vụ tối ưu hóa
-
metacrank
n m metacrankthiết lập việc đánh giá theo chu kỳmcho phần tử nằm sâunphần tử dưới đỉnh stackcranktương đương với0 m metacrank- Mỗi token chỉ có thể có một metacrank được áp dụng để đánh giá, và metacrank thấp hơn có ưu tiên cao hơn
- metacrank và crank không chỉ áp dụng với token trong file mà còn cả quá trình đánh giá đệ quy các định nghĩa từ
- metacrank cho phép thao tác trực tiếp lên cú pháp kiểu như “đọc thêm n token rồi mới thực thi token này”
- Sau khi lập trình xong các từ prefix thì có thể
undefchúng nếu không còn cần nữa - Có thể tạo ký tự prefix dừng sau một số lượng token nhất định thay vì chờ một ký tự kết thúc cụ thể
- Có thể đưa đầu vào người dùng vào một chương trình toán học, rồi chuyển đầu ra của nó cho một hệ cú pháp như metacrank
Quá trình phát triển thành phương ngữ Stem
- Sau bootstrap, Cognition dần dần xây dựng từ bên trong ngôn ngữ một cú pháp gần với Stem v2
- Trước hết,
fbị xóa khỏi danh sách falias và chỉ để lạiing- Nếu đặt trực tiếp
flên stack thì nó sẽ bị thực thi, nên người ta tạoffrồi cắt chuỗi làm đôi để lấy ra haif - Sau đó
fđược định nghĩa thành một từ rỗng tương ứng với false
- Nếu đặt trực tiếp
-
Chú thích
#- Ký tự
#là ví dụ mã đầu tiên hoạt động như một prefix thực sự - Ký tự chú thích này hoạt động như một prefix bỏ đi toàn bộ văn bản cho đến trước newline, tạo nên dạng cú pháp mà parser phải nhìn về phía trước
- Cách hiện thực kết hợp
geti,getd,gets,crankbase,halt,VMACRO cast,singlet,delimv.v. geti,getd,getslần lượt lấy ra chuỗi ignore, delimiter, singlethaltđưa mọi metacrank về 0VMACRO castbiến container trên đỉnh stack thành macro- Định nghĩa
#thay đổi quy tắc token hóa, rồi gọi#trên từ sẽ được token hóa trong tương lai, bỏ phần chú thích đó đi và sau cùng quay lại crank cùng metacrank ban đầu
- Ký tự
-
escape, quote, macro
\\được định nghĩa thành ký tự escape cho phép đưa cả những từ lẽ ra sẽ được đánh giá lên stack- Sau đó thêm định nghĩa quote
[rồi lại dùng chính quote đó để tự định nghĩa lại một[tốt hơn có hỗ trợ quote đệ quy - Nhờ
defhậu tố, có thể dùng định nghĩa cũ để tạo ra định nghĩa mới - Đây là kiểu phát triển thường gặp trong Cognition mức thấp
(được định nghĩa làm dấu ngoặc macro- Macro được thiết kế để tự động expand, và tác giả cho rằng bind một macro đã được expand sẵn vào từ sẽ hiệu quả hơn
- Về mặt chức năng thì nó vẫn được đánh giá theo cùng cách
expandmở rộng đệ quy các định nghĩa từ bên trong quote hoặc macro bằngunglue- Trước tiên định nghĩa
expandcơ bản, rồi dùng chínhexpandđể định nghĩa lại nó cho các trường hợp tổng quát hơn
Phương ngữ Brainfuck
- Trên phương ngữ Stem đã phát triển, Cognition định nghĩa một phương ngữ Brainfuck
- Ví dụ chạy là
../crank -s 2 bootstrap.cog helloworld.bf brainfuck.cog brainfuck.cogkhông phải parser Brainfuck theo nghĩa thông thường- Nó định nghĩa các từ Brainfuck
- Nó token hóa Brainfuck
- Nó chạy Brainfuck trong môi trường native của Cognition
- Ví dụ này cho thấy cú pháp Cognition có thể định nghĩa cú pháp thay thế rất dễ dàng
- Thay vì đọc ký hiệu rồi quyết định hành động theo ký hiệu đó, Cognition dùng metacrank để định nghĩa chính các ký tự prefix thành từ, qua đó đặt cú pháp vào trong định nghĩa từ
Ý tưởng dialect dialect
- Có thể tưởng tượng ra một từ như
mkprefix- Ví dụ, đó là từ nhận hai từ đầu vào
[và]cùng một phép toán nào đó, rồi tự động định nghĩa để[áp dụng phép toán cho đến khi gặp]
- Ví dụ, đó là từ nhận hai từ đầu vào
- Ý tưởng này khả thi vì cả
metacranklẫndefđều là từ thông thường - Vì mọi thứ, kể cả
d,i,s, đều là từ, nên có thể tạo ra những phương ngữ trừu tượng hơn để tự động hóa quá trình hiện thực cú pháp - Dù thư viện chuẩn chưa triển khai, đây là các mục đã được bàn với Matthew Hinton như khả năng cho thư viện chuẩn
- metaword tự động tạo và gọi các từ trừu tượng
- tìm kiếm word-generator để tự động trừu tượng hóa wordlist hiện tại
- một cách chỉ dẫn framework trừu tượng hóa nhằm giải quyết vấn đề
Khả năng coi cú pháp như mã
- Trong Cognition, xử lý chuỗi tương đương với hậu xử lý tokenizer, nên các phép toán chuỗi mang ý nghĩa rất mạnh
- Các lĩnh vực ứng dụng tiềm năng gồm Symbolic AI, nghiên cứu cú pháp và grammar, thử nghiệm prototype cho ngôn ngữ và metalanguage
- Cũng có các ý tưởng như chương trình đọc file cấu hình, shell dựa trên Cognition, hay hệ điều hành dựa trên Cognition
- Cốt lõi là Cognition cho phép biến “syntax as code” thành hiện thực
- Có thể lập trình cú pháp một cách động
- Có thể tự động hóa chính việc sinh ra cú pháp
- Các khái niệm như Metastack và
cdchưa được đề cập, và được để lại cho các bài viết tiếp theo
1 bình luận
Ý kiến trên Hacker News
Ví dụ, trong Racket có thể tạo một triển khai Datalog nhúng, dùng cú pháp Datalog nhưng vẫn tương tác được với các mô-đun Racket khác, và mô hình dữ liệu cơ bản không thay đổi
Đây là cách cho phép metaprogramming mà không bị mắc kẹt trong S-expression, đồng thời xử lý ở mức cao hơn
Kiểu bootstrap cú pháp như vậy rất hay và có giá trị nghiên cứu, nhưng tôi không rõ nó có tốt hơn về căn bản so với cách tiếp cận của Racket hay không
Macro của Lisp, Scheme, Racket thường hoạt động trên AST, nhưng Rhombus hoạt động trên “shrubbery”, thứ giống AST nhưng trì hoãn một số quyết định parsing về sau, nhờ đó cho việc mở rộng cú pháp thêm chút linh hoạt
Tham khảo: https://docs.racket-lang.org/guide/hash-reader.html, https://docs.racket-lang.org/datalog/datalog.html, bài báo Rhombus https://doi.org/10.1145/3580417
#langcủa Racket dễ dùng hơn readtable của CLChỉ riêng readtable cũng đủ mạnh để triển khai cả một trình biên dịch C: https://github.com/vsedach/Vacietis
Cá nhân tôi đã bật cười ở đoạn “metacrank” xuất hiện
Trong Emacs Lisp, Common Lisp, ISLISP, macro chỉ nhận dữ liệu nào đó và trả về dữ liệu nào đó; không có khái niệm như AST
Khi gọi
(foo-macro ...),...có thể là dữ liệu tùy ýVí dụ,
(defmacro rev (&rest items) (reverse items))chỉ nhận danh sách đối số nguồn của lời gọi macro rồi đảo ngược nóCó thể dùng như
(rev 1 2 3 4 +)hoặc(rev (rev 10 n -) (+ a 20 b) (rev 30 a *) list), và thực tế thứ được truyền vào là list, số và symbolNó không phải văn bản, cũng không phải AST; ngay cả khi truyền dữ liệu đã tính toán cho
evalthì nó vẫn hoạt động theo cùng cáchReader của Lisp về cơ bản đọc symbolic expression, tức tầng dữ liệu, còn EVAL, macro và các chức năng khác chủ yếu nhận dữ liệu
Trình biên dịch có thể tạo biểu diễn AST nội bộ, nhưng đó là quyền tự do triển khai; ngôn ngữ Lisp thường được định nghĩa trên cú pháp dữ liệu chứ không phải cú pháp văn bản
Trình thông dịch Lisp là “List Processor” xử lý S-expression trong lúc chạy chứ không xử lý văn bản, và
COMPILEcũng nhận S-expression chứ không nhận văn bảnRacket và Scheme có hệ thống macro riêng
Phải hơn 300 từ mới nhắc đến dự án thực tế là Cognition; phần nói về Lisp cũng hay, nhưng tôi nghi ngờ đó có phải phần quan trọng nhất của dự án không
Khi đọc một bài viết cung cấp thông tin, tôi luôn tự hỏi “có đáng bỏ thời gian không?”, nên tài liệu cần cho biết ngay từ đầu nó nói về gì
Chỉ cần kiểu như “Cognition là một ngôn ngữ mới khám phá cú pháp do người dùng chỉnh sửa được” là đủ, nhưng sau bốn đoạn đầu tôi vẫn khó đánh giá liệu có đáng đọc tiếp hay không
Nếu thời gian là tiền bạc, thì có thể xem thời gian đọc bài này là lãng phí
Thay vì kỳ vọng mọi nội dung trên Internet phải phù hợp với sở thích cá nhân, tôi nghĩ tốt hơn là thích nghi với các hình thức đã có
Văn bản không phải phương tiện buộc phải tiêu thụ tuần tự như video, nên có thể đọc lướt để tìm phần thú vị; nếu không có thì bỏ, còn nếu có thì quay lại đầu để đọc
Các lối viết đa dạng tốt hơn vì buộc ta phải có ý thức lọc thông tin mình tiêu thụ; nếu chỉ tiêu thụ thụ động thì đầu óc sẽ lười đi
Tuy nhiên nếu là video thì tôi sẽ đồng ý
Với video, phải quyết định có đầu tư thời gian trước khi xem hay không; xem tốc độ 2x hoặc tua 5–10 giây có giúp chút ít nhưng không giải quyết được vấn đề
Cấu trúc là giải thích vấn đề trước rồi sau đó giới thiệu giải pháp
Chỉ đọc vài câu là tôi đã hiểu đây là một giải pháp kiểu Don Quixote cho một “vấn đề” mà 99,999% người, kể cả người như tôi từng nghe về Lisp nhưng chưa dùng ngoài file cấu hình Emacs, sẽ chẳng quan tâm; dù vậy tôi vẫn cứ đọc tiếp
Nếu không có đoạn như vậy, phần sau sẽ khó hiểu hơn
Nếu không biết nền tảng đó, có thể bỏ lỡ ngữ cảnh của toàn bài, và cũng khó đánh giá đây có phải lập luận người rơm hay không
Vì vậy toàn bộ thứ này tạo cảm giác như tồn tại cho một nhu cầu rất hẹp, trong khi tiêu đề thì tổng quát hơn nhiều và trông như một khái niệm khá thú vị
Chỉ trong hai câu đầu đã lộ ra vấn đề cần giải quyết là gì, và với tôi điều đó hữu ích hơn nhiều so với phần mở đầu được đề xuất để tự đánh giá mức độ quan tâm
Tuy vậy, cá nhân tôi khi nhìn lên chiếc thang của sự thuần khiết trong lập trình thì Forth có lẽ là giới hạn độ thuần khiết triết học mà tôi chịu nổi
Chúng tôi dự định sẽ tiếp tục bàn về nhiều hắc thuật hơn nữa
Chỉ có điều hầu như mọi ngôn ngữ, kể cả tất cả các Lisp, đều xử lý quotation sai, và buồn cười là
m4lại là ngoại lệLisp обход qua vấn đề này bằng macro, cho phép xử lý các câu lệnh của ngôn ngữ meta được biểu diễn bằng câu lệnh của ngôn ngữ đối tượng mà bỏ qua việc trích dẫn
Vấn đề này phát sinh từ việc cả ngôn ngữ đối tượng lẫn ngôn ngữ meta đều coi khoảng trắng là điểm kết thúc của nguyên tử, nhưng lại không phân biệt hai bên
Cách tiếp cận của Cognition, một loại phản cú pháp hoàn toàn hậu tố, trông giống các ngôn ngữ lập trình nối kết, nhưng ngôn ngữ hậu tố là đối ngẫu của ngôn ngữ tiền tố và gặp cùng vấn đề
Hoặc phải định trước số ngôi của mọi symbol và không dùng hàm bậc cao, hoặc cần một cặp dấu phân cách để có thể tuần tự hóa cây
Dựa vào stack bậc 0 ngầm định thì giống như phẫu thuật cắt thùy trán để chữa trầm cảm vậy
Chúng tôi cũng không biết mình đã tạo ra thứ mới đến mức nào, và nếu bạn nghĩ Lisp có thể làm được việc chúng tôi làm thì cứ chứng minh rằng chúng tôi sai
m4Bản thân lập luận thì thú vị, nhưng cần cụ thể hơn
Cũng có thể xem việc quay lại cách nguyên thủy nhất để tính toán chuỗi lệnh là tương tự, giống như phẫu thuật cắt thùy trán làm giảm năng lực xử lý bậc cao
https://www.hpmuseum.org/rpnvers.htm
Đặc biệt tôi thích việc cơ chế đó rất nhỏ gọn
Tôi không phải chuyên gia ngôn ngữ nên không biết nó có mới hay không, nhưng trong suốt lúc đọc bài, tôi cảm nhận được niềm vui của các tác giả khi mỗi lần vượt qua một ngọn đồi lại phát hiện ra cả một dãy núi khả năng mới
Nếu tôi hiểu đúng, câu chuyện là với Cognition có thể thực sự tạo ra một cỗ máy biết suy nghĩ
Chương trình không cần bị dừng rồi khởi động lại bằng lệnh mới; nó có thể tự viết và thực thi các subroutine mới dựa trên đầu vào mới
Tức là chương trình có thể học và thích nghi bằng cách tạo ra các abstraction mới và kết nối với API mới
Với tôi, hướng này thú vị hơn các mạng nơ-ron lớn hơn hay những kỹ thuật học mới
Common Lisp có reader macro, nên bạn có thể thay đổi cú pháp tùy ý, và còn có cả compiler Fortran đọc cú pháp Fortran bằng reader macro
Common Lisp có reader macro ở thời điểm đọc, macro, compiler macro ở thời điểm biên dịch, và tất cả các ngôn ngữ macro này đều là Common Lisp
Metaprogramming không liên quan nhiều đến macro hay cú pháp, mà chỉ khả năng thao tác ngữ nghĩa và ý nghĩa của type, interface, class, method, v.v.
Nếu bản thân CL chưa đủ mạnh cho việc đó thì có CLOS, tức Common Lisp Metaobject Protocol
Với reader macro của CL, có thể dùng tokenizer khác, nhưng phải báo việc chuyển tokenizer bằng một biểu thức trong read table
Trong Cognition, có vẻ như khi gọi một hàm thì tokenizer của ngữ cảnh caller thay đổi
Lý do tôi được học rằng những việc như thế này với máy Turing hay lambda calculus là quan trọng, là để cho thấy ngôn ngữ cấp cao tương đương với ngôn ngữ nền tảng, từ đó những gì suy luận được về cái trước cũng có thể áp dụng cho cái sau
Ví dụ đầu tiên và duy nhất tôi nghĩ đến là bài toán dừng
Ở quy mô thực dụng, nếu chứng minh được ngôn ngữ cơ sở không bị rò rỉ bộ nhớ, liệu có thể nói các ngôn ngữ phái sinh cũng không bị rò rỉ không?
Tôi tò mò việc bootstrap kiểu này có lợi ích gì
Nếu câu trả lời đơn giản là kiểu leo Everest vì "nó ở đó", thì tôi cũng tôn trọng
df, khoảng trắng ở dòng 3, và dấu xuống dòng là quan trọng, tôi lập tức "cảm ơn nhưng xin kiếu"Ba ký tự khoảng trắng ở cuối dòng trước biểu thị sự mỉa mai; ở những nơi không thể dễ dàng phân biệt khoảng trắng cuối dòng, cứ diễn giải theo nghĩa đen là được
Phần bootstrap được nhắc tới thực ra là đoạn nói với người đọc hãy coi khoảng trắng và xuống dòng là dấu phân cách
Nói cách khác, bạn đang phàn nàn rằng khoảng trắng có ý nghĩa trong đoạn khai báo nó là dấu phân cách
Tất nhiên bạn có quyền nghĩ vậy, nhưng tôi tự hỏi liệu có cách nào làm tốt hơn không
Tôi không nghĩ ra cách nào làm được việc này mà không có một lần khoảng trắng literal mang ý nghĩa theo kiểu đó
Bạn có nghĩ mình có thể đọc một câu như "sentence this without you syntax read can" mà không có cú pháp không?
Cognition nói là dùng phản cú pháp hoàn toàn hậu tố, nhưng hậu tố cũng là cú pháp
Cứ hỏi người nói tiếng Đức về động từ ở cuối câu là biết
Ngay trong ví dụ đầu tiên, thứ tự của toán hạng và toán tử cũng quan trọng, và đó chính là cú pháp
Đây có vẻ là một nỗ lực tạo ra một ngôn ngữ nén đến mức phi lý, khiến tôi nhớ nhiều đến APL
Gợi ý cho các tác giả: các bạn không loại bỏ cú pháp, mà chỉ làm nó khó đọc và khó hiểu hơn đối với con người; khả năng đọc và khả năng hiểu là các yếu tố quan trọng trong lập trình
Cảm giác như luật dưới chân cứ liên tục thay đổi, các luật và từ được đưa vào rồi bị tái định nghĩa tùy tiện
Nhìn chung có vibe giống Numberwang, nên đó có vẻ là một trong những lý do nó được tiếp nhận như một tác phẩm châm biếm
Một lý do lớn khác là giai đoạn bootstrap được viết đến mức buồn cười, mà có vẻ là có chủ ý
Rõ ràng có điều gì đó sâu sắc ở đây, nhưng tôi sẽ phải đọc lại sau khi uống cà phê đậm hơn
Tôi là tác giả bài này, vấn đề là có thật sự rất nhiều nội dung cần truyền đạt
Tôi đã trao đổi với Matthew về thiết kế ngôn ngữ này vài giờ mỗi ngày trong suốt 3 tuần, và cũng có nhiều ngữ cảnh cần bổ sung cho những người thực sự không biết tôi