- Là một ngôn ngữ nhỏ chạy trên runtime Go trong khi sử dụng cú pháp kiểu Rust, kết hợp ưu điểm của cả hai ngôn ngữ
- Cấu trúc tăng cường độ an toàn và khả năng biểu đạt với kiểu dữ liệu đại số, pattern matching, hệ thống kiểu Hindley-Milner, tính bất biến mặc định
- Đảm bảo khả năng tương tác với hệ sinh thái Go thông qua import trực tiếp package Go, toán tử pipeline, khối
try, đồng thời dựa trên task
- Cải thiện trải nghiệm lập trình viên và độ ổn định của mã với phát hiện lỗi khi biên dịch, thông báo chẩn đoán rõ ràng, hỗ trợ LSP
- Điểm cốt lõi là mã Lisette được chuyển thành mã Go rõ ràng, dễ đọc, nên có thể tích hợp tự nhiên với các dự án Go hiện có
Tổng quan về Lisette
- Lisette là một ngôn ngữ nhỏ dựa trên cú pháp Rust và được biên dịch sang runtime Go
- Có các đặc trưng như kiểu dữ liệu đại số, pattern matching, không có
nil, hệ thống kiểu Hindley-Milner, tính bất biến mặc định, khả năng tương tác với hệ sinh thái Go
- Có thể cài đặt bằng lệnh
cargo install lisette, và có thể import trực tiếp các package như fmt, io, os của Go để sử dụng
Cú pháp quen thuộc
- Có cấu trúc cú pháp tương tự Rust
- Hỗ trợ pattern matching thông qua
enum và match
- Có thể định nghĩa phương thức bằng
struct và khối impl
- Là ngôn ngữ hướng biểu thức, trong đó
if, let, các block đều trả về giá trị
- Hỗ trợ chaining và lambda, giúp biểu đạt ngắn gọn việc xử lý biến môi trường hoặc thao tác chuỗi
- Hỗ trợ interface và generic, có thể viết hàm generic thông qua định nghĩa
interface và ràng buộc T: Trait
- Có thể xử lý ngắn gọn kiểu
Option bằng cú pháp if let và let else
Tính an toàn
-
Phát hiện ở thời điểm biên dịch các lỗi có thể xảy ra trên runtime Go
- Nếu không xử lý hết mọi pattern trong câu lệnh
match thì sẽ phát sinh lỗi
- Không cho phép dùng
nil, biểu diễn giá trị thiếu bằng Option<T>
- Cảnh báo nếu bỏ qua giá trị trả về Result
- Cảnh báo khi làm lộ kiểu không công khai trong API công khai
- Lỗi khi truyền biến bất biến làm đối số có thể thay đổi
- Lỗi biên dịch khi thiếu field của struct
- Thông báo chẩn đoán cung cấp vị trí mã cụ thể và gợi ý cách sửa
- Hỗ trợ LSP (Language Server Protocol) nên có thể dùng trong các editor phổ biến như VSCode, Neovim, Zed
Tính tiện dụng
- Được thiết kế với trọng tâm là khả năng tương tác với Go
- Dùng toán tử pipeline (
|>) để biểu đạt function chaining ngắn gọn
- Đơn giản hóa việc lan truyền lỗi thông qua khối
try
- Đồng thời được triển khai tương tự goroutine của Go bằng
task và Channel
- Có thể chỉ định tên field JSON, bỏ qua field, chuyển đổi sang chuỗi, tag kiểm chứng... bằng attribute tuần tự hóa
- Cung cấp khối
recover để phục hồi panic, và có thể xử lý lỗi an toàn bằng kiểu Result
- Hỗ trợ cú pháp defer để đảm bảo dọn dẹp tài nguyên hoặc rollback transaction
Kết quả biên dịch minh bạch
- Mã Lisette được chuyển thành mã Go rõ ràng và dễ đọc
- Kiểu
Option và Result lần lượt được chuyển thành struct lisette.Option và lisette.Result
- Cú pháp
match được chuyển thành câu lệnh điều kiện của Go để xử lý từng nhánh
- Toán tử
? được thay thế nội bộ bằng mã kiểm tra Result
- Ví dụ, hàm
classify nhận Option<int> rồi được chuyển thành các câu lệnh điều kiện tường minh của Go; hàm combine thì được chuyển thành mã Go kiểm tra Result
Thông tin thêm
- Kho lưu trữ chính thức: github.com/ivov/lisette
- Được phát hành theo giấy phép MIT, và tính đến năm 2026 do Iván Ovejero phát triển
1 bình luận
Ý kiến Hacker News
Tôi đã trò chuyện với tác giả và dù chưa trực tiếp dùng ngôn ngữ này, Lisette có vẻ khá thú vị và rõ ràng là một cải tiến so với Go
Tuy vậy, tôi nghĩ sẽ khó có thể vượt qua hoàn toàn các giới hạn của Go. Ví dụ, vấn đề
typed nilxuất phát từ kiểu interface của Go được xử lý bằng Option trong Lisette, nhưng việc unwrapping hai lớp (Some(Some(h))) có thể trở nên gượng gạoNgoài ra, cách dùng defer của Go vẫn còn bất tiện và không có cơ chế giải phóng tài nguyên tự động kiểu RAII
TypeScript bổ sung cho JavaScript vì không có lựa chọn thay thế nào chạy được trên trình duyệt, nhưng giờ đã có WASM nên tình hình đã khác
Vì vậy tôi tự hỏi: “Đã có Rust rồi thì tại sao còn muốn biến Go thành Rust?” Dù vậy, có vẻ Lisette đang nhắm tới điểm ở giữa
Cuối cùng, Lisette có vẻ phù hợp với những ai muốn cải thiện codebase Go hiện có hoặc vẫn muốn tiếp tục dùng runtime Go
Điều tôi thắc mắc là thiếu một hướng dẫn bắt đầu nhanh trả lời câu hỏi: “Nếu muốn viết file sau bằng Lisette thay vì Go thì phải bắt đầu như thế nào?”
Bài blog liên quan: Go is still not good
Trong những miền bài toán phải xử lý đồ thị tham chiếu phức tạp, GC là thứ thiết yếu, và nhờ cấu trúc stack ở user mode nên Go có mô hình bộ nhớ hiệu quả
Go cũng phù hợp để làm các công cụ CLI nhanh kiểu này — ví dụ: wordle-tui
Cú pháp đơn giản, hỗ trợ đa nền tảng, runtime và GC tích hợp sẵn, mô hình “errors as values”, green thread, trình biên dịch AOT nhanh... đều là các ưu điểm lớn
defercủa Go hữu ích, nhưng xử lý lỗi và quy tắc scope vẫn khá gượngTypeScript cũng không giải quyết được vấn đề này, thậm chí còn tệ hơn. Vì vậy tôi đã tự viết một gói kiểu Option rồi đưa lên NPM → fp-sdk
Đã có khá nhiều ngôn ngữ biên dịch sang Go — như XGo, Borgo, Soppo
(T, error)bằng kiểu Result, nhưng về mặt ngữ nghĩa thì không hoàn toàn giống nhauVí dụ
io.Reader.Readdùng(n!=0, io.EOF)để biểu thị kết thúc bình thường, nên nếu chỉ coi đó là lỗi thì sẽ dẫn đến hành vi saiChất lượng thông báo lỗi của Lisette rất ấn tượng. Các gợi ý “help” thực sự hữu ích
Tuy nhiên, tôi lo rằng mã sau khi chuyển sang Go có thể trở nên dài dòng, nên khi gặp lỗi runtime thì sẽ phải debug trong mã Go
Ngoài ra, chiều gọi Lisette từ code Go hiện có cũng có vẻ khó
Tôi cũng muốn biết Lisette là một ngôn ngữ thử nghiệm hay đang hướng tới sản xuất thực tế
lis run --debugthì trong mã Go sẽ được chèn chú thích//line source.lis:21:5để stack trace được ánh xạ về mã Lisette gốcLSP xử lý lỗi compile-time dựa trên file
.lisHiện chưa có tính năng gọi Lisette từ Go, nhưng ưu tiên trước mắt là import package Go từ Lisette
Ban đầu đây là một thử nghiệm, nhưng mục tiêu là phát triển nó thành ngôn ngữ ở mức production
Tôi thắc mắc vì sao không mang nguyên cú pháp giống Rust vào luôn
Ví dụ: dùng
use foo::barthay choimport "foo.bar", hayBar::Baz =>thay choBar.Baz =>Người biết Rust sẽ thấy rối, còn người không biết Rust thì cũng không chuyển giao được kiến thức sang Rust
intvàfloat64tuân theo quy ước đặt tên kiểu của Go.thay vì+Runtime của Go thì tốt, nhưng bản thân ngôn ngữ lại thô và có vẻ không có ý định cải thiện
Vì thế nếu đã phải dùng transpiler thì chắc hẳn là phải ghét Go lắm
Tôi thắc mắc vì sao Rust hay các ngôn ngữ họ Rust lại tách struct và method ra
Tại sao không thể định nghĩa method trực tiếp bên trong struct?
Ngoài ra, khối impl có thể có ràng buộc generic khác với struct, nên có thể định nghĩa nhiều impl khác nhau
Cuối cùng, Rust là ngôn ngữ được thiết kế để người dùng tư duy xoay quanh hình dạng dữ liệu (Shape)
Nếu có một ngôn ngữ trông như Python nhưng biên dịch sang Rust hoặc Go thì sẽ rất tuyệt
Lisette có vẻ là ngôn ngữ cân bằng tốt giữa sự đơn giản của Go và sự phức tạp của Rust
Tôi tò mò không biết có lý do gì khiến tốc độ biên dịch của nó chậm hơn Go nhiều hay không, và có những phần nào của Rust đã được chủ đích loại bỏ
Ví dụ: borrow checking, kiểu dữ liệu, async...
Go là ngôn ngữ dễ học nhưng thiếu tính năng
Lisette trông như một ngôn ngữ lấp đầy những khoảng trống đó, nên khá thú vị
Nếu giống như TypeScript mở rộng JavaScript, việc bổ sung cho Go một hệ thống kiểu giàu khả năng biểu đạt và một trình biên dịch nghiêm ngặt có thể tạo ra một ngôn ngữ backend rất tốt
Gợi ý cá nhân của tôi là hỗ trợ chia sẻ kiểu với frontend TypeScript. Đây cũng là một trong những lý do TypeScript được ưa chuộng ở backend
Với tư cách là một lập trình viên tự động hóa hạ tầng đang phân vân giữa độ an toàn của Rust và sự đơn giản của Go, ý tưởng mang tính dễ dùng của Rust đặt lên trên runtime Go là cực kỳ hấp dẫn
Tôi sẽ tiếp tục theo dõi sự phát triển của dự án này