3 điểm bởi GN⁺ 2023-07-28 | 1 bình luận | Chia sẻ qua WhatsApp
  • Trong mạch suy nghĩ về một ngôn ngữ vẫn có thể dùng được trong tương lai, lần lựa chọn này gần với việc trực tiếp thử nghiệm một quy trình phát triển hiện đại dù ngôn ngữ đã cũ hơn là tính thực dụng
  • Janet là một ngôn ngữ script nhỏ thuộc họ Lisp/Clojure, nhắm đến phạm vi tương tự Lua, và đã thu hút sự chú ý nhờ thư viện chuẩn cùng metaprogramming dựa trên macro
  • Tính di động, khả năng nhúng và Parsing Expression Grammars của Janet trông có vẻ hấp dẫn, nhưng hiện tại chỉ khớp một phần hạn chế với nhu cầu; các lựa chọn sẵn có như CHICKEN Scheme, CLISP, SBCL và Packrat cũng đã đủ thuyết phục
  • Phát triển theo REPL của Common Lisp có điểm cốt lõi là ở trạng thái lỗi lúc chạy, có thể xem stack, biến và dữ liệu sống, chỉnh sửa chúng rồi tiếp tục phần thực thi đã bị gián đoạn
  • Dù phải trả giá để học một ngôn ngữ mới và thư viện chuẩn mới, tác giả cho rằng vẫn đáng để tự mình trải nghiệm môi trường mà quy trình này đã được tính đến ngay từ khi thiết kế

Vì sao sự quan tâm chuyển từ Janet sang Common Lisp

  • Tác giả vốn muốn viết mã có thể dùng lâu dài nên thường suy nghĩ về future-proof programming languages, nhưng khi tạo ra thứ gì đó để chia sẻ thì lại chọn cách tiếp cận thực dụng: ưu tiên ngôn ngữ phổ biến, có tính di động và tiện dụng
  • Mặt khác, tác giả cũng tìm hiểu các ngôn ngữ và công cụ khác để vui và thử nghiệm
    • Đã theo dõi những ngôn ngữ thú vị có tên ngắn như NimZig
    • Những thử nghiệm như vậy đôi khi giúp phát hiện ra cách lập trình mới hoặc những công cụ sau này trở thành thiết yếu
  • Gần đây, sau khi đọc cuốn sách miễn phí Janet for Mortals, tác giả bắt đầu quan tâm đến Janet
    • Janet là một ngôn ngữ script tương đối nhỏ, lấy cảm hứng từ Lisp/Clojure và nhắm đến một ngách tương tự Lua
    • Nó cung cấp thư viện chuẩn thực thụ, metaprogramming kiểu Lisp và khả năng thực thi ở thời điểm biên dịch thông qua macro
  • Ngoài chất Lisp nói chung, những điểm hấp dẫn nhất ở Janet là tính di động, khả năng nhúng và Parsing Expression Grammars
    • Hiện tại tác giả không cần nhúng ngôn ngữ, nên khả năng nhúng không phải là lý do quyết định
    • Về tính di động, CHICKEN Scheme, CLISP, và Steel Bank Common Lisp cũng có vẻ ổn
    • Với bài toán phân tích cú pháp, Packrat có vẻ là một lựa chọn hợp lý
  • Kết quả là số lý do để chọn Janet thay vì một Lisp đã có từ trước ngày càng ít đi

Quy trình phát triển theo REPL đã khiến tác giả học Common Lisp

  • Một bài viết nói về quy trình phát triển theo REPL gần như là độc nhất của Common Lisp đã trở thành động lực học tập
  • Tình huống ví dụ là khi hàm foo gọi hàm bar chưa được định nghĩa, và lỗi xảy ra trong lúc chạy foo
    • Trong các môi trường Lisp cũ hoặc Smalltalk, việc foo bị gián đoạn sẽ dẫn vào breakloop
    • breakloop là một REPL đầy đủ nằm trong môi trường động của hàm bị gián đoạn
    • Có thể di chuyển qua lại trong call stack đã bị tạm dừng và kiểm tra các biến nhìn thấy ở từng stack frame
    • Có thể kiểm tra và sửa dữ liệu sống của chương trình đang chạy
    • Nếu nguyên nhân là do một biến hoặc giá trị trường bị sai, có thể sửa giá trị đó rồi tiếp tục hàm đã bị gián đoạn
    • Cũng có thể định nghĩa hàm bar còn thiếu ngay trong REPL rồi tiếp tục foo để nhận được kết quả hợp lý
  • Tác giả từng thấy nhiều tính năng kiểu “edit and continue”, nhưng việc Common Lisp được tạo ra với kiểu quy trình này ngay từ đầu là điều đem lại cảm giác mới mẻ
  • Trải nghiệm gỡ lỗi trước đây của tác giả đã chuyển từ printf debugging sang dùng debugger thực thụ
    • printf debugging là cách tạm chèn mã log, biên dịch lại rồi xem kết quả chạy
    • Trong những tình huống không thể sửa chương trình hoặc chạy lại, tác giả buộc phải học debugger
    • Debugger thực sự là công cụ đúng đắn, nhưng việc thiết lập môi trường gỡ lỗi có thể rất đau đầu hoặc đôi khi là bất khả thi
  • Common Lisp có vẻ như là môi trường đẩy việc gỡ lỗi tiến thêm một bước
    • Tác giả từng có trải nghiệm sửa bộ nhớ trong debugger để thử các bản sửa tiềm năng
    • Nhưng điểm đặc biệt hấp dẫn là có thể viết lại và vá mã ngay bên trong tiến trình đang chạy
  • Mục tiêu khi học Common Lisp là tự mình kiểm chứng xem cách xây dựng chương trình một cách tương tác này có phải là một lối làm việc thú vị hay không
  • Tác giả không chắc việc học một ngôn ngữ mới và thư viện chuẩn mới có phải là lựa chọn tốt nhất chỉ để khám phá một workflow mới hay không, nhưng cũng chưa thấy lựa chọn thay thế nào rõ ràng hơn
    • Những ngôn ngữ khác cũng có thể có tích hợp REPL-trình soạn thảo tương tự
    • Tuy vậy, tác giả cho rằng các tính năng như thế có thể nhiều lỗi hơn vì là thứ được thêm vào sau, chứ không được hỗ trợ ngay từ đầu
    • Ngay cả khi cuối cùng không hài lòng, ít nhất tác giả vẫn đã thử nó trong điều kiện tốt nhất với bộ công cụ tiêu chuẩn
  • Những tài liệu giúp học Common Lisp đã được tổng hợp trong bài viết riêng Common Lisp resources

1 bình luận

 
GN⁺ 2023-07-28
Ý kiến trên Hacker News
  • Không ngờ lại thấy bài viết của mình ở đây. Một ngày nào đó tôi cũng muốn viết bài tiếp theo, nhưng hiện giờ vẫn còn là người mới
    Những điểm tôi thích ở Common Lisp cho đến nay là hệ thống điều kiện rất gọn gàng, và nhờ restart, có thể dễ dàng điều khiển cả những đoạn mã nằm ở xa. Phát triển theo hướng REPL cũng rất tiện trong những tình huống chưa biết rõ chuyện gì sẽ xảy ra, chẳng hạn khi phân tích một nguồn dữ liệu lạ, vì có thể sửa mã và tiếp tục mà không mất ngữ cảnh
    Có nhiều implementation và khả năng tương tác cũng tốt, nên trong một trường hợp tôi đã có thể thay đổi qua lại giữa SBCL để lấy tốc độ và CLISP để giảm mức dùng bộ nhớ. Một trong những lý do tôi nghiêng về CL hơn Scheme khi học Lisp cũng là vì có nhiều implementation tương thích
    Dù tôi còn mới với Emacs, phần tích hợp Common Lisp vẫn rất tuyệt, và chạy tốt ngay cả trên chiếc netbook rất chậm dùng để phát triển. Trong thời đại có máy tính nhanh, VS Code và language server như hiện nay thì đây không còn là lợi thế quá lớn, nhưng rõ ràng nó có cảm giác retro-future
    Cũng có vài điểm tiếc nuối. Trình quản lý gói phổ biến nhất QuickLisp thì ổn, nhưng chưa đạt đến mức tính năng mà ta đã quen trong các hệ sinh thái ngôn ngữ hiện đại. Bản thân ngôn ngữ như bị cố định trong thời gian, nên rất nhiều thứ như thread, đồng bộ hóa, đối số dòng lệnh đều cần thư viện tương tác chung. Và tôi thật sự mong SBCL hỗ trợ build tĩnh hoàn toàn để có thể phân phối binary cho cả các bản phân phối Linux không dùng glibc
    • Cũng có vài nhược điểm. Lần cuối tôi kiểm tra, QuickLisp chỉ tải gói qua HTTP dạng plaintext, không có mã hóa cũng không có cơ chế xác minh để phát hiện việc bị sửa đổi trong quá trình truyền
      Nếu một tác vụ quan trọng như tải mã nguồn mà không hỗ trợ mã hóa hay xác thực, tôi nghĩ QL khó có thể là lựa chọn cho những người quan tâm đến bảo mật
      Việc SBCL được host trên SourceForge cũng là vấn đề. SourceForge từng chèn mã độc vào kho tải xuống trong quá khứ, nên tôi cũng xem đây là vấn đề bảo mật. Ngày nay dường như không có lý do thuyết phục nào để tiếp tục dùng SourceForge, nên tôi không rõ vì sao một dự án quan trọng vẫn còn ở đó
      Tôi thật sự thích Lisp, đặc biệt là Common Lisp, nhưng những điều này khiến tôi rời xa, và dường như cũng không có nhiều sự quan tâm đến việc sửa chúng
    • Nếu cần build tĩnh và có thể dùng một bản SBCL hơi cũ, công trình của daewok, người đã build và liên kết SBCL trong môi trường musl, có thể là giải pháp bạn đang tìm. Tôi đã thử chuyển patch sang phiên bản mới hơn, nhưng do các thay đổi upstream nên vẫn còn bị segmentation fault
      https://www.timmons.dev/posts/static-executables-with-sbcl.h...
      https://www.timmons.dev/posts/static-executables-with-sbcl-v...
    • Tôi tặng bạn một cons
      https://cons.io
      Gerbil/Gambit Scheme có thể tạo binary tĩnh hoàn toàn như một lựa chọn thay thế cho CL
    • Tôi đang làm CIEL dành cho những lúc muốn bắt đầu với một bộ thư viện tốt (json, csv, cơ sở dữ liệu, HTTP client, đối số dòng lệnh, mở rộng ngôn ngữ, v.v.): https://github.com/ciel-lang/CIEL/
      Có thể dùng như thư viện Quicklisp thông thường, như core image khởi động tức thì, hoặc như binary. Script cũng có thể chạy gần như ngay lập tức, nên có vài điểm giống Babashka. Vẫn đang trau chuốt chi tiết và chưa phải v1.0
      Phần trong blog về “xử lý lỗi runtime bằng cách sửa mã bị hỏng ngay tại chỗ mà không cần khởi động lại” lẽ ra nên được minh họa ở đây: https://www.youtube.com/watch?v=jBBS4FeY7XM
      Khi chạy một phép tính dài và nặng rồi gặp lỗi ở bước cuối, thay vì chạy lại từ đầu, bạn vào debugger tương tác, chuyển đến dòng lỗi, biên dịch hàm đã sửa, rồi quay lại debugger và tiếp tục thực thi từ một điểm trong stack frame. Sau đó có thể thấy chương trình chạy qua
  • Ở chỗ làm tôi dùng Clojure, nhưng mỗi khi cần debug hoặc cần mã chạy nhanh, tôi lại nhớ gần như mọi thứ của Common Lisp. Việc có thể nhấn vào bất kỳ phần nào của stack bên trong các lỗi lồng nhau để xem lexical binding cực kỳ hữu ích, và cách nhấp vào một đối tượng rồi dùng M- để sao chép nó vào REPL theo tôi tốt hơn nhiều so với tap> mà Clojure cung cấp. Ngay cả khi dùng công cụ như Portal, tôi vẫn thấy tap> gần giống một dạng pretty-print được tô điểm hơn
    Về hiệu năng, Common Lisp cũng cho phép chỉ định kiểu tĩnh, và SBCL có thể tạo ra mã rất hiệu quả khi làm như vậy. Chạy DISASSEMBLE trên mã tự viết để xem thực sự thứ gì được phát ra rồi tối ưu hóa là việc hữu ích. Đặc biệt các gói như SB-SIMD và Loopus thật sự giúp ích rất nhiều cho ứng dụng tính toán số
    • Bạn đã tóm tắt rất đúng những bất mãn tôi cảm thấy khi viết luận văn thạc sĩ bằng Clojure. Không phải tôi bất mãn với lựa chọn đó. Clojure rất phù hợp với thiết kế game kiểu entity-component-system, vì nó kết hợp tốt cảm giác “mọi thứ đều là map khóa-giá trị” với cách làm “nếu khóa :quack là true thì hãy xử lý nó như vịt”
      Nhưng trong suốt một năm qua, tôi thật sự nhớ cách phát triển của Common Lisp, và trên đời này là hệ thống điều kiện. Tôi thậm chí không phải hacker CL thành thạo đến vậy, nhưng nó đã nhanh chóng trở thành thói quen. Ước gì CLOS và các kiểu dữ liệu nguyên thủy của CL hòa hợp với nhau tốt hơn vẻ ngoài của chúng
    • Trong Clojure, flowstorm rất đáng xem thử. Nó cho phép bước qua lại bên trong hàm, và có thể gửi map cùng với các hàm đó sang REPL
    • Tôi nghĩ không ngôn ngữ nào trong hai ngôn ngữ này tự thân cung cấp tính năng gửi form tới REPL; đó là tính năng của công cụ
      Trong Cider thì chắc chắn có thể làm dễ dàng, và tôi nghĩ các công cụ chính trên những editor khác cũng làm được tương tự ở mức đủ tốt
    • Trong Clojure cũng có thể làm phần nào việc tương tự DISASSEMBLE

Có các dự án hỗ trợ như https://github.com/Bronsa/tools.decompiler, và cũng có JitWatch của OpenJDK (https://github.com/AdoptOpenJDK/jitwatch). Các JVM khác cũng có những công cụ tương tự
Không trực quan bằng Lisp, nhưng vẫn làm được

  • Steel Bank Common Lisp là con ngựa thồ đã giúp tôi xây dựng được một công ty phần mềm có lợi nhuận. Nếu không có nó, tôi nghĩ mình đã không thể làm việc hiệu quả đến vậy. Quy trình làm việc dẫn dắt bởi REPL rất tuyệt, image của Lisp cực kỳ vững chắc, và hiệu năng cũng cao
    • Có thể chia sẻ các công ty đó là những công ty nào cho những người tò mò không?
    • Trông rất hay, nhưng giờ tôi quá lười để quay lại Emacs. Chủ yếu khi phát triển Python và JavaScript tôi dùng VSCode gần như cấu hình mặc định. Tôi giữ vai trò CTO nên cũng không code toàn thời gian
    • Tôi cho rằng thời mà stack công nghệ còn quan trọng dù chỉ một chút phần lớn đã qua rồi
      Tạo ra được một thứ bí hiểm nào đó chạy tốt và hấp dẫn thì cũng hay, nhưng giờ sẽ chẳng ai muốn chạm vào nó ngoài những người có thể mô tả lương của mình bằng số lượng chữ số 0
    • Người ta nói quy trình làm việc dẫn dắt bởi REPL thật đáng kinh ngạc, nhưng có vẻ họ không biết rằng ngày nay hầu như mọi ngôn ngữ chạy trên máy ảo/interpreter đều có REPL
      https://www.digitalocean.com/community/tutorials/java-repl-j...
      https://github.com/waf/CSharpRepl
      https://pub.dev/packages/interactive
      Chưa kể Ruby, Python, PHP, Lua; ngay cả C++ cũng có REPL dù còn thô sơ: https://github.com/root-project/cling
      Mỗi lần tôi nói rằng REPL trong thế giới Lisp không còn là yếu tố khác biệt nữa thì lại bị downvote
  • Nếu bạn quan tâm đến đồ họa 3D, có một codebase Common Lisp đáng xem. Tôi đã cố giữ nó đơn giản và dễ hiểu
    https://github.com/kaveh808/kons-9
    • Nên tìm xem các video hướng dẫn CL của Kaveh trên YouTube. Chúng được làm thật sự tốt
  • Với tư cách là một lập trình viên Clojure, break loop và quy trình làm việc dẫn dắt bởi REPL trông rất hay, và chắc chắn sẽ hữu ích cho Clojure. Nó có thể khiến việc code frontend bằng JS/TypeScript với các công cụ debug tuyệt vời của trình duyệt trở nên giống hơn. Đáng tiếc là hiện trạng công cụ và hỗ trợ cộng đồng trong hệ sinh thái Clojure có vẻ khá nghèo nàn
    • Với Clojure, nếu đó là trường hợp các lời gọi nằm sâu trong các tầng code diễn ra theo từng request, như web server, thì cũng có thể mô phỏng phần nào luồng REPL thật sự. Khi server vẫn đang chạy, bạn có thể viết lại và reload nhiều hàm rồi gửi lại request từ trình duyệt
      Tuy nhiên việc định nghĩa lại và ghi đè như vậy rốt cuộc sẽ làm ô nhiễm namespace, và đến một lúc nào đó sẽ có thứ gì đó hỏng khiến phải reload server
  • Tôi thích CL và thật sự nhớ nó khi làm việc khác. So với trải nghiệm Lisp từ nhiều thập kỷ trước, rất nhiều việc trong các ngôn ngữ “hiện đại” đau đớn đến mức chẳng buồn cười nổi
    Nó cũng có nhiều nhược điểm, nhưng không tệ hơn các nhược điểm thuần kỹ thuật của hầu hết mọi ngôn ngữ và môi trường phát triển khác. Python và JS được dùng rộng rãi hơn và có nhiều thư viện hơn, nhưng tôi cảm thấy trải nghiệm phát triển tệ hơn nhiều. Tôi đã dùng C#, TS, Py, Hs và cả những ngôn ngữ bí hiểm hơn trong nhiều năm, nhưng mỗi khi bị mắc kẹt trong các ngôn ngữ đó hoặc nổi giận nghiêm trọng vì những thứ rõ ràng là tệ, tôi lại quay về CL(SBCL + Emacs + Slime). Khi đó tôi thấy nhẹ nhõm và có niềm tin rằng trên đời vẫn còn những điều tốt đẹp
    Hiện chúng tôi đang gọi vốn cho một sản phẩm mà chúng tôi đã ngu ngốc bootstrap bằng TypeScript, nhưng phiên bản phát hành sẽ được làm lại bằng CL. Điều đó có nghĩa là trong 3–5 năm tới trước khi ra mắt, chúng tôi sẽ làm việc bằng CL, bên trong CL, và tôi rất vui vì sẽ được làm những việc thú vị như triển khai DSL, sinh code, làm macro, triển khai bộ phân tích kiểu tĩnh
    • Không thể có Lisp mà không có cons
      Khi làm việc bằng C#, bạn nhớ điều gì ở Lisp?
    • Vì sao TypeScript không phù hợp với sản phẩm đó?
  • Trong blog và các bình luận của tác giả ở đây có nhiều chuyện về “coding”, nhưng hầu như không thấy nói họ đang xây dựng loại phần mềm nào và nhắm đến các use case nào
    Suy nghĩ cực đoan của tôi là lý do lập trình hàm không phổ biến rộng rãi là vì nó rõ ràng ổn cho việc viết chương trình, nhưng phần lớn phần mềm ngày nay không phải là “chương trình chạy từ dòng lệnh trên PC/server của tôi cho đến khi kết thúc”, mà là “chương trình khởi động rồi phản hồi input của người dùng cho đến khi người dùng đóng lại”, hoặc “chương trình khởi động rồi phản hồi mạng hay các I/O tự động khác cho đến khi phần mềm khác bảo nó dừng”
    Những việc như vậy khó hơn nhiều nếu làm theo phong cách hàm thuần túy, hoặc ít nhất là như vậy trong các triển khai hàm có quan điểm mạnh mà tôi từng dùng. Vì khi đó không còn chỉ đơn giản là đánh giá một biểu thức nữa, mà là khởi tạo trạng thái, phản ứng với I/O, cập nhật trạng thái hoặc thực hiện thêm I/O, thậm chí dùng song song hóa để giám sát, nhận dữ liệu, thực hiện thêm I/O và cập nhật trạng thái
    Tất nhiên không phải là không thể làm những việc này bằng Lisp, nhưng từ vài học kỳ tiếp xúc với lập trình hàm thời đại học và kinh nghiệm dùng các tính năng hàm một cách chuyên nghiệp trong C++/Scala để giải các vấn đề như vậy, tôi thấy việc làm cho lập trình hàm vận hành tốt trong các ứng dụng kiểu này khá khó, và sự không phù hợp đó khiến tôi ngần ngại đi sâu hơn vào lập trình hàm
    • Nhận xét hay. Hiện tại tất cả chỉ là sở thích. Những thứ tôi làm bằng Common Lisp chỉ là một client Battlesnake bình thường và một game đảo chữ nhiều người chơi vừa bị đóng cửa hôm qua. Cả hai đều không thu được lợi ích lớn nhờ làm bằng Lisp, nhưng tôi đã học được rất nhiều trong quá trình đó, và đó mới là điều cốt lõi

Ngoài Common Lisp, tôi cũng thường xuyên gặp việc phải viết mã tạo ra mã. Ở lĩnh vực này Lisp có vẻ sẽ tỏa sáng, nhưng tôi chưa có cơ hội thử. Ví dụ các dự án gần đây tôi làm trước khi nghĩ đến Common Lisp gồm tạo mã kiểm tra một JSON Schema cụ thể trong trình tạo site tĩnh, và tạo JSX từ Markdown để dùng cho nội dung cốt truyện của một game lập trình
Chưa kể vô số macro C tôi đã dùng suốt thời gian qua

  • Common Lisp hiện vẫn có CLOS, một trong những hệ thống hướng đối tượng tiên tiến nhất. Phần lớn Lisp không phải là ngôn ngữ hàm như Haskell
  • Elixir dùng lập trình hàm, và rất xuất sắc khi cần phát triển web hoặc hệ thống chịu lỗi
    Cũng không cần vứt bỏ hết các tính năng hay của những phong cách khác. Một phần của lập trình hàm đang ngày càng phổ biến hơn trong các ngôn ngữ thông thường. Ví dụ Rust cũng dùng các mẫu hàm trong nhiều trường hợp
    Và Lisp cũng có thể được dùng theo phong cách hướng đối tượng hoặc mệnh lệnh nếu muốn. Nó không phải Haskell
  • Tôi mất một thời gian để hiểu monad và IO monad, và còn mất lâu hơn để học cách hợp thành chúng một cách an toàn và điều khiển thứ tự thực thi. Nhưng giờ tôi có thể viết ứng dụng an toàn về kiểu, và ngay cả khi làm việc với ngôn ngữ không phải hàm cũng ít tạo bug hơn. Ngôn ngữ tôi được trả tiền để dùng là Java
    Tôi xem Lisp là điểm khởi đầu, còn Haskell mới là thứ thật sự. Khuyên nên học phong cách đó, dù không viết mã production thực tế
  • Common Lisp không phải ngôn ngữ “thuần hàm” mà hỗ trợ mọi mô hình lập trình. Nó cho phép cả những thứ kỳ lạ như thế này
    (let ((pair (cons 1 nil)))
    (setf (cdr pair) pair)
    (list (first pair) (second pair) (third pair)))
    ;; => (1 1 1)
  • Nếu muốn “chạy mãi mãi” thì viết bằng Rust
    Nếu muốn “biên dịch mãi mãi” thì viết bằng ANSI C
    Nếu muốn “tồn tại mãi mãi” thì viết bằng Python 2.7 và biến nó thành xương sống của các template hạ tầng cho toàn tổ chức. Có module Ansible tùy chỉnh thì được cộng điểm
  • Như câu “vì là năm 2023 nên hiển nhiên tôi đang học Common Lisp”, tôi cũng đang học, nhưng các tính năng được nhắc đến vẫn chưa thấy hữu ích với mình. Có thể khi quen hơn tôi sẽ đổi ý
    Điều tôi mong là Lisp giúp biểu đạt suy nghĩ thành mã dễ hơn bằng cách giảm thiểu hoặc trừu tượng hóa những thứ lặt vặt và boilerplate. Với tôi, biểu thức Lisp trông như cách tự nhiên nhất để diễn đạt suy nghĩ
    Tôi chủ yếu quan tâm đến viết ứng dụng GUI, nên muốn học Clog hoặc tìm hay phát triển một wrapper tốt trên một GUI toolkit nào đó
  • Điểm cốt lõi là Scheme và Janet cũng rất tuyệt, nhưng tác giả muốn một ngôn ngữ độc lập hơn. Thứ tạo ra khác biệt là breakloop, một REPL đầy đủ mở ra khi chương trình gặp lỗi. Không phải stack trace hay debugger, mà là cách xây dựng tiếp ngay tại điểm hiện đang bị hỏng
    • Nghe thật sự ấn tượng, vậy tại sao Common Lisp không phải ngôn ngữ phổ biến nhất? Tôi hỏi với tư cách người hầu như không viết mã
    • Với tư cách lập trình viên Clojure, tôi thấy khá thú vị nhưng tò mò trong trường hợp sau sẽ thế nào. Đây không phải mã kiểu Lisp, chỉ là ví dụ để chỉ ra chỗ tôi không hiểu
      (do-it (do-it first))
      (do-it first) hoạt động tốt, nhưng nếu lời gọi (do-it (do-it first)) thất bại thì sao?
      Sẽ rất hay nếu có thể giành quyền điều khiển tại điểm hỏng và sửa định nghĩa do-it. Nhưng nếu sửa thì kết quả của (do-it first) cũng thay đổi
      Khi đó vị trí hiện tại của máy trở thành một điểm không còn có thể đi tới bằng mã hiện tại nữa
      Tôi thật sự không hiểu cơ chế này hoạt động ra sao trong trường hợp một sửa đổi giúp chương trình tiếp tục lại làm thay đổi chính trạng thái mà ta đã nhận quyền điều khiển để sửa
    • Nghe nói tại điểm lỗi mở ra một REPL đầy đủ, không phải stack trace hay debugger mà là xây dựng trực tiếp từ điểm hỏng hiện tại, làm tôi muốn mở thử một image Smalltalk nhỏ
    • Điều này cũng là chuẩn trong Gambit Scheme
    • Những thứ như vậy trong production có trở thành đường tấn công cho mã độc hoặc lỗ hổng bảo mật không?