Rời xa Haskell
(journal.infinitenegativeutility.com)- Một lập trình viên từng dùng Haskell làm ngôn ngữ chính từ khoảng năm 2009 đến khoảng năm 2019 nay không còn xem Haskell là lựa chọn mặc định cho dự án cá nhân hay khi tìm việc
- Sức hấp dẫn của Haskell không nằm ở monad hay DSL tự thân, mà ở khả năng suy luận mã theo đại số, tái cấu trúc an toàn nhờ hệ thống kiểu mạnh, và khả năng biểu diễn các bất biến
- Lý do dần rời xa là do sự tích lũy của văn hóa ưa chuộng các tính năng kiểu nâng cao, công cụ chưa mượt mà, cùng những thay đổi không tương thích liên tục trong GHC và thư viện chuẩn
- Dù vậy, các hàm bậc cao, cú pháp
do, lens, thư viện khai báo, và các trừu tượng kiểu nâng cao vẫn là những ưu điểm mà ngôn ngữ khác khó thay thế dễ dàng - Haskell rất đáng học để trở thành lập trình viên giỏi hơn, nhưng nếu chọn làm ngôn ngữ mặc định cho tổ chức thì cần chấp nhận cái giá của chất lượng công cụ và độ ổn định ngôn ngữ
Thời kỳ dùng Haskell làm ngôn ngữ mặc định và vị trí hiện tại
- Trong khoảng 10 năm, Haskell là ngôn ngữ mặc định cho các dự án mới
- Sau khi tiếp xúc với Haskell vào khoảng năm 2009, tác giả xem mình là một lập trình viên Haskell cho đến khi chuyển sang nơi làm việc chủ yếu dùng Ruby và C++ vào khoảng năm 2019
- Haskell được dùng cho nhiều mục đích như công cụ dòng lệnh, dịch vụ web, ứng dụng đồ họa, và các script nhỏ
- Hiện tại tác giả không hoàn toàn từ chối Haskell, nhưng nó không còn là ngôn ngữ mặc định ngay cả trong dự án cá nhân, và cũng không còn chủ động tìm “công việc Haskell” như trước
- Nhận định này không phải kết luận rằng Haskell là ngôn ngữ tệ, mà gần hơn với việc giải thích vì sao cá nhân tác giả đã dần rời xa nó
Vì sao từng bị Haskell thu hút
-
Tính chất cho phép xử lý mã theo kiểu đại số
- Điểm hấp dẫn lớn nhất của Haskell là có thể suy luận mã một cách ký hiệu và đại số
- Ví dụ, nếu có hàm
double n = n + nthì phép biến đổidouble xthànhx + xtrong Haskell luôn là đúng - Trong nhiều ngôn ngữ mệnh lệnh,
double(i++)và(i++) + (i++)có thể cho kết quả khác nhau- Trường hợp đầu tăng
imột lần - Trường hợp sau tăng
ihai lần
- Trường hợp đầu tăng
- Nhờ tính chất này, có thể tích lũy các phép biến đổi cơ học nhỏ để thực hiện những lần tái cấu trúc lớn an toàn hơn
- Việc tái cấu trúc lớn trong codebase Ruby có thể rất bất an, nhưng trong codebase Haskell thì dễ chịu hơn nhiều
-
Hệ thống kiểu nghiêm ngặt nhưng không quá ồn ào
- Hệ thống kiểu của Haskell rất nghiêm ngặt nhưng nhờ suy luận kiểu, không cần viết quá nhiều chú thích kiểu như Java
- Typeclass cũng giúp giảm bớt phiền toái trong các tình huống phải quan tâm tới kiểu
- Mã Haskell tốt có tính chất “dễ vỡ đúng cách” (
brittle)- Một trừu tượng sai không âm thầm bị bẻ cong để cho phép chương trình sai chạy qua
- Nếu có vấn đề, quá trình biên dịch sẽ thất bại
- Kiểu
NonEmptybiểu diễn danh sách có ít nhất một phần tử- Các phép toán giữ nguyên độ dài như
mapsẽ trả vềNonEmpty - Các phép toán làm tăng độ dài như
appendcũng trả vềNonEmpty - Các phép toán mà kết quả có thể rỗng như
filtersẽ trả về danh sách thường
- Các phép toán giữ nguyên độ dài như
- Nếu một hàm yêu cầu danh sách đường dẫn tệp phải là
NonEmpty, thì không thể truyền trực tiếp đối số dòng lệnh vào đó mà phải kiểm tra trước là không rỗng - Nếu sau này thêm bước lọc theo phần mở rộng, kết quả có thể rỗng nên phải kiểm tra lại, và trình biên dịch sẽ chặn các đường đi vô tình truyền danh sách rỗng
-
Duy trì bất biến bằng kiểu
- Dùng Haskell lâu dần sẽ quen với cách biểu diễn bất biến của chương trình bằng kiểu và để trình biên dịch xác minh
- Điều này không chỉ có nghĩa là các phép tính phức tạp ở mức kiểu
- Có thể phân biệt trạng thái đã escape SQL hay chưa bằng các kiểu bọc như
RawStringvàSanitizedString- Dù web API trả về
RawString, tầng cơ sở dữ liệu có thể được thiết kế chỉ nhậnSanitizedString
- Dù web API trả về
- Cũng có thể chuyển từ biểu diễn bề mặt với nhiều trường
Maybesang biểu diễn nội bộ bảo đảm rằng thông tin cần thiết luôn tồn tại - Ngoài ra còn có thể chỉ làm cho mã generic ở mức đủ để kiểm thử độc lập
-
Một ngôn ngữ tự nhiên cho DSL và hàm bậc cao
- Haskell giúp tạo ra ngôn ngữ chuyên biệt theo miền ngắn gọn ngay cả khi không có macro
- config-ini là một ví dụ về thư viện xử lý tệp cấu hình INI
- Thay vì giao diện phân tích kiểu mệnh lệnh, nó dùng giao diện khai báo
- Ánh xạ một phần cụ thể của kiểu cấu hình vào một phần cụ thể của cấu trúc tệp INI
- Cùng một giao diện được dùng cho đọc, ghi, và cập nhật tối thiểu theo diff
- DSL trong Ruby có thể dựa vào metaprogramming động và monkeypatching toàn cục, còn DSL trong Haskell dễ giới hạn vào một tệp hay vùng mã cụ thể hơn nhờ cú pháp linh hoạt và các tính năng như overload monad
- Haskell cũng khiến việc dùng hàm bậc cao trở nên tự nhiên
(+)có thể được dùng ngay như một hàm nhận hai đối số số và cộng chúng- Có thể biểu diễn phép nhân từng cặp phần tử của hai danh sách rất ngắn gọn như
pairwiseProduct = zipWith (*)
- Có thể ví Haskell với Perl theo nghĩa: Perl khiến việc thao tác chuỗi trở nên thuận tay, còn Haskell khiến việc thao tác hàm trở nên thuận tay
Ba yếu tố khiến dần rời xa Haskell
-
Bầu không khí ưa chuộng phong cách khó nhằn
- Yếu tố đầu tiên là sự ưa chuộng cái mới trong phong cách
- Cộng đồng Haskell liên tục thử nghiệm và xây dựng các trừu tượng mới
- Những cách tiếp cận lấy cảm hứng từ đại số trừu tượng hay lý thuyết phạm trù
- Những cách tiếp cận đẩy nhiều tính toán hơn lên mức kiểu để giới hạn trạng thái sai
- Type-level web API của Servant hay trường hợp biểu diễn hệ thống menu bằng comonad là các thử nghiệm nhằm biểu diễn miền bài toán theo cách mới
- Nhưng trong mã công việc hằng ngày, những cách tiếp cận mang tính thử nghiệm như vậy thường tạo ra nhiều vấn đề hơn lợi ích ban đầu mà chúng thể hiện
- Trong một ví dụ ở dự án trình biên dịch, các nút AST mang kiểu biểu thức như tham số kiểu
- Nếu tạo ra cây cú pháp có lỗi kiểu, bản thân trình biên dịch sẽ không biên dịch được
- Ban đầu điều này có bắt được một số lỗi
- Nhưng khi nhiều pass tối ưu hóa không khớp với kỷ luật kiểu, mã trở nên phức tạp vì phải ép kiểu và xoa dịu GHC
- Cuối cùng tham số kiểu đã bị loại khỏi AST
- Trong khoảng ba phần tư các dự án từng thử hướng “fancy types”, tác giả đánh giá rằng giá trị nhận lại không đủ đáng
- Trào lưu Simple Haskell dựa trên ý tưởng rằng có thể nhận được nhiều lợi ích nhất của ngôn ngữ khi tránh các tính năng thử nghiệm và chỉ dùng số lượng extension tối thiểu
- Các tính năng kiểu phức tạp hơn đã lan rộng trong cộng đồng và thư viện
- Các trừu tượng kiểu phức tạp có thể khiến việc thay đổi và bảo trì khó hơn, và tác giả từng trải nghiệm việc cố thay một trừu tượng đã đơn giản hóa bằng trừu tượng kiểu cấp cao mới hơn dẫn đến mã lớn hơn, hiệu năng kém hơn, và khó đọc hơn
- Tuy vậy, những tính năng kiểu mức cao “cầu kỳ” như Trees that Grow, nơi cấu trúc dữ liệu được đánh chỉ số theo từng giai đoạn của trình biên dịch, vẫn là ví dụ hữu ích
-
Công cụ không thật sự tỏa sáng trong công việc hằng ngày
- Yếu tố thứ hai là hệ công cụ gượng gạo
- Haskell có nhiều hệ thống build và công cụ phát triển gần như đóng vai trò tiêu chuẩn
- Nhìn chung các công cụ này làm được việc cần làm, nhưng chưa đạt tới mức “đáng để yêu thích”
- Có những công cụ như
ormoluhoàn thành nhiệm vụ với mức phiền toái tối thiểu, nhưng một số công cụ khác đòi hỏi phải liên tục đối phó với bug và tìm đường vòng - Công cụ Haskell đã cải thiện trong 10 năm, nhưng tính đến năm 2019 vẫn chưa có công cụ nào đạt mức dễ dùng và ổn định như Rust Cargo
- Xu hướng Not-Invented-Here, luôn muốn tạo ra thứ mới và tốt hơn, cũng là một vấn đề
- Thậm chí còn có xu hướng xử lý lại cả định dạng văn bản gói bằng hpack
- Thật khó chịu khi những nỗ lực như vậy cứ ở trạng thái hoàn thành 95% trong nhiều năm
- Đây không phải nhận xét rằng công cụ Haskell là tệ hại, nhưng mức “cũng tạm ổn” không còn đáp ứng tiêu chuẩn đã tăng lên
-
Những thay đổi không tương thích kéo dài
- Yếu tố thứ ba là sự thay đổi liên tục của ngôn ngữ Haskell và GHC
- Trên thực tế, GHC được xem như triển khai Haskell công khai duy nhất đủ hợp lý
- Haskell cố gắng dần sửa các sai lầm và điểm thiếu nhất quán trong quá khứ, kể cả ở thư viện chuẩn và những phần nền tảng của ngôn ngữ
- Những thay đổi này có thể đưa ngôn ngữ tới một nền tảng sạch sẽ và nhất quán hơn, nhưng với người dùng thì lại tạo ra ma sát nhỏ liên tục
- Foldable-Traversable Prelude changes năm 2015 là một ví dụ cho kiểu thay đổi này
- Các dự án Haskell cũ có thể không build được trên GHC mới ngay cả khi không có phụ thuộc bên ngoài
- thêm superclass
- xóa import
- thêm type signature vì polymorphism trở nên mơ hồ
- Các chỉnh sửa thường nhỏ, nhưng cứ tích tụ dần và những chỗ hơi khác so với trước liên tục đòi hỏi người dùng phải để ý
- Điều này tương phản với cách cập nhật theo epoch của Rust, nơi có cam kết tương thích ngược cho các tính năng ổn định và các breaking change có chủ đích được giấu sau từng epoch
Những ưu điểm của Haskell vẫn còn được nhớ tới
- Cách viết mã và tái cấu trúc theo kiểu đại số của Haskell vẫn là một thế mạnh
- Rust cũng chia sẻ nhiều ưu điểm với Haskell, nhưng để chắc chắn rằng một lần tái cấu trúc cơ học nhỏ vẫn giữ nguyên ý nghĩa chương trình thì không dễ như trong Haskell
- Hệ thống kiểu của Haskell cũng vẫn cung cấp những khả năng mà các ngôn ngữ khác thường không có
- Các ngôn ngữ chủ đạo năm 2023 đã tiến bộ rất nhiều về kiểu tĩnh so với năm 2009
- Dù vậy, các tính năng như những trừu tượng xây trên higher-kinded types vẫn là điểm khác biệt của Haskell
- Hệ sinh thái thư viện Haskell khá lẫn lộn
- các thư viện mã nguồn mở được duy trì nửa vời
- những vương quốc nhỏ nơi từng tác giả riêng tái kiến tạo thế giới theo cách của mình
- nhiều kiểu gần giống chuỗi khác nhau, đều cần thiết nhưng không tương thích nhau
- Dù vậy, Haskell vẫn có các thư viện và trừu tượng tuyệt vời mà ở ngôn ngữ khác chỉ làm được một nửa
- lens là một trừu tượng mạnh, khó thấy hết lợi ích nếu chưa dùng đủ lâu
- Brick cung cấp một thư viện UI terminal rất tốt bằng các khối khai báo
- diagrams và music-suite cũng là những ví dụ hay về API khai báo
- Cú pháp
docũng là một tính năng rất đáng nhớ- Điều cốt lõi không hẳn là bản thân
do, mà là một kiểu ký pháp cho phép thêm binding mà không khiến mức thụt lề cứ tăng mãi flat_maplồng nhau trong Ruby sẽ khiến thụt lề ngày càng sâu khi số chiều tăng lên- Cú pháp
dotrong Haskell biểu diễn cùng một cách kết hợp đó theo dạng phẳng
- Điều cốt lõi không hẳn là bản thân
- Cú pháp
docòn cho phép nhúng những thứ như đồng thời có cấu trúc kiểuasync/await, giao dịch đồng thời, hay chương trình xác suất dưới cùng một lớp cú pháp nhẹ nhàng
Có nên học hay dùng Haskell không
- Câu trả lời cho “có nên học hay dùng ngôn ngữ này không” phụ thuộc vào mục tiêu
- Nếu mục tiêu là trở thành lập trình viên giỏi hơn, Haskell rất đáng học
- Haskell là một ngôn ngữ thú vị và mạnh mẽ
- Tác giả đánh giá rằng việc học Haskell đã nâng cao năng lực lập trình của mình
- Nếu mục tiêu là sử dụng thực tế, thì nên cân nhắc kỹ hơn
- Các ưu điểm của Haskell là có thật
- Cần so sánh chúng với mức ma sát mà cá nhân hay tổ chức sẵn sàng chấp nhận như đã nói ở trên
- Vẫn có những cá nhân và tổ chức nhận được đủ lợi ích từ Haskell để giữ các bất tiện nhỏ chỉ ở mức vết xước nhỏ
- Nếu buộc phải trả lời dứt khoát có hay không, thì câu trả lời nghiêng về “đừng dùng Haskell”
- Nếu phải xây dựng một tổ chức kỹ thuật, tác giả sẽ không chọn Haskell làm ngôn ngữ mặc định
- Vì tác giả hiểu cả giá trị của công cụ tốt lẫn chi phí của công cụ tệ
- Tác giả ưu tiên các ngôn ngữ có thể cung cấp ngay một môi trường ngôn ngữ ổn định, hệ sinh thái mã rõ ràng, và công cụ xuất sắc
- Dù vậy, Haskell vẫn cung cấp những công cụ tuyệt vời cho độ an toàn và tính đúng đắn của chương trình
- Trong một số bối cảnh nhất định, có thể vẫn đáng chấp nhận công cụ chưa tốt và linting để ngăn những
type familykhông cần thiết
- Trong một số bối cảnh nhất định, có thể vẫn đáng chấp nhận công cụ chưa tốt và linting để ngăn những
- Haskell không còn là ngôn ngữ phù hợp với cá nhân tác giả nữa, nhưng tác giả kết luận rằng nếu Haskell không tồn tại trên đời thì thế giới sẽ tệ hơn
1 bình luận
Ý kiến trên Hacker News
Tôi đã dùng Haskell khoảng 10 năm rồi gần đây rời khỏi nó như một phương tiện kiếm sống, và chắc chắn đồng ý với điểm đầu tiên của tác giả: cộng đồng Haskell rất coi trọng việc học hỏi
Làm việc với những người tò mò, nơi luôn có điều để dạy và học, là điều tốt, nhưng cộng đồng lại khá yếu trong việc bỏ đi các ý tưởng đã thử; vì vậy các codebase Haskell chuyên nghiệp, nếu không được quản lý nghiêm ngặt, rất dễ tích tụ nhiều thứ kiểu “làm được, nhưng tốt nhất là không nên dùng”
Tuy nhiên, về toolchain thì tôi có ý kiến khác. Đúng là công cụ của Haskell không hay lắm, nhưng sau khi dùng Python, JS, Java, Rust, Elm, tôi thấy phần lớn công cụ cũng chẳng hay, và ngược lại còn nhớ toolchain của Haskell. cargo rất tuyệt nhưng gần như là ngoại lệ, và tôi tò mò liệu Rust có tránh được tình trạng này khi nó già đi hay không
Có một dự án tôi thỉnh thoảng làm, và tôi chắc 100% rằng lần sau mở ra nó sẽ lại không chạy. Quản lý phụ thuộc và môi trường ảo của Python cũng tệ tương tự, nhưng Poetry khá ổn; Ruby thì dù dùng chruby/rbenv/rvm cái nào cũng hoạt động tốt tương tự, Bundler cũng chạy ngon. Java có khuyết điểm, nhưng trải nghiệm IDE thuộc hàng tốt nhất, và dù refactoring không an toàn bằng Haskell, nó vẫn rất dễ thực hiện
Bundler nhìn chung không tệ; dù có những lựa chọn thiết kế tôi không đồng ý, nếu đi theo đúng đường thì rất nhiều thứ khớp với nhau tốt. Công cụ ngôn ngữ cũng có thể được làm theo cách đủ ít hỏng hóc; tôi chưa dùng cargo nhiều trực tiếp, nhưng nếu nó thật sự là tốt nhất trong lớp thì việc nó duy trì trạng thái đó cũng không đáng ngạc nhiên
Về mặt công cụ, Haskell có một thứ mà theo tôi biết thì các ngôn ngữ khác khó cạnh tranh: Hoogle
Hoogle tốt đến mức đáng kinh ngạc. Bạn nói bằng Haskell điều mình muốn, nó cho bạn biết những gì có thể làm bằng Haskell. Rust cũng từng có những nỗ lực tương tự, và tôi cũng từng thử làm Noogle cho Nim, nhưng ở các ngôn ngữ mà “truyền đối số cho hàm” và “gọi hàm” được phân tách rõ ràng, nó không hoạt động theo cùng cách
Mỗi khi nhìn code Rust có
Result,Boxđan xen, tôi lại ước có một Roogle hữu ích như Hoogle. Ngoài ra, công cụ Haskell không có ưu điểm gì. Phần lớn có vẻ là do bản năng của cộng đồng muốn tạo ra thứ gì đó “đột phá” thay vì cải thiện cái đã cóNó chưa hoàn hảo, nhưng so với 5 năm trước thì tốt hơn hẳn
Tôi mong nhiều dự án hơn đi theo hướng này
Tôi nghĩ vấn đề lớn nhất là GHC bị ràng buộc với một phiên bản
basecụ thể, vốn là thư viện chuẩnKhi
basethay đổi và phiên bản GHC mới chỉ hỗ trợ phiên bản đó, về cơ bản bạn phải thay đổi mọi phụ thuộc để dùng GHC mới hơn. Tôi vẫn chưa hiểu vì sao code biên dịch bằng GHC 9.6 lại phải dùngbase4.18.0.0. Tại sao binary GHC phải quan tâm đến phiên bản moduleData.Listcủa code được biên dịchTôi hiểu rằng các thành phần dành riêng cho GHC mà
basephơi bày thì bị ràng buộc với một phiên bản GHC cụ thể, nhưng không rõ vì sao phần còn lại cũng phải như vậy. Tuy nhiên, tôi hiểu là đang có công việc chiabasethành nhiều package để sửa điều này: https://gitlab.haskell.org/ghc/ghc-wiki-mirror/-/blob/master...basecũ vì coi nó không hợp lệbasekhác nhau trao đổi các instanceData.Listcho nhau thì sẽ phát sinh vấn đềVí dụ, khi có một danh sách của
Data.List, liệu bạn có thể nối kết quả của hai hàm thư viện khác nhau vào danh sách đó khôngbasecó thể cài đặt lại là mục tiêu mà mọi người đều mong muốn. Tình trạng hiện tại chủ yếu do lý do lịch sử và do các phần tử cơ bản gắn với nội bộ compiler bị kết hợp với các phần tử không cơ bản; nếu bỏ đủ công sức thì có thể cải thiện đượcNếu có ba lý do lớn khiến sự quan tâm đến Haskell dần nguội đi, thì đó là khuynh hướng chuộng cái mới về phong cách, tôn vinh những đoạn mã khó hiểu khiến việc bảo trì trở nên khó khăn; công cụ gượng gạo làm các công việc hằng ngày chậm chạp hơn; và những thay đổi liên tục, dù chỉ thỉnh thoảng nhưng vẫn đều đặn phải để tâm và định kỳ phá vỡ mọi thứ
Đây là nhận xét xác đáng. Vào giai đoạn 2010–2012 tôi học Haskell khá nhiều; bản thân ngôn ngữ thì tuyệt vời, nhưng tài liệu và công cụ rất khó xử lý. Cộng đồng đi từ Cabal và “Cabal hell” khét tiếng sang Stack, rồi lại quay về Cabal, và nhìn chung mọi thứ đã tốt hơn
Trong khi đó, các ngôn ngữ lập trình khác cũng đã hấp thụ các yếu tố lập trình hàm. Ví dụ Java đã thêm Streams, hàm, lambda, kiểu dữ liệu đại số, records, pattern matching; cú pháp có thể không thanh nhã như Haskell, nhưng các khái niệm cơ bản của lập trình hàm đều đã có mặt
Như thế họ tự tạo ra một hố đau khổ vô tận cho chính mình, và nó chỉ vừa đủ chịu đựng được vì chùm sáng không xuống đủ thấp để thấy được màu sắc mà ánh sáng tạo ra trên cái cây ngoài cửa sổ. Những người đến từ bên ngoài nhanh chóng mất trí, bị xé giữa phương ngữ đã thích nghi với bóng tối do họ tự tạo ra và phương ngữ có thể phát triển mạnh trong ánh sáng nhưng lại ngạt thở ở nơi đó
Nếu cộng đồng đã quay lại Cabal, tôi tò mò không biết mình đã bỏ lỡ điều gì
Vì những lý do này mà tôi chuyển sang F# và hầu như không ngoái lại. Thỉnh thoảng tôi cũng nhớ higher-kinded types, nhưng F# cũng có generics, và nói thật thì nó có phần buộc tôi viết mã đơn giản hơn so với khi dùng Haskell, nên nhìn chung kết quả tốt hơn
Tuy vậy F# không đem lại cảm giác “cao thủ” như Haskell. Nó giống Haskell nhưng hoàn toàn thực dụng. Tôi làm được rất nhiều việc bằng F# và dùng nó rất vui, nhưng đôi khi vẫn bâng khuâng nhìn lại và tự hỏi vì sao mình với Haskell lại không thành
Tôi thường tự hỏi liệu không dùng Haskell có phải là đang bỏ lỡ điều gì không, nhưng với mục đích của tôi thì có lẽ không
Học Haskell giống như cố giải mã một ngôn ngữ ngoài hành tinh. Nếu bạn đã quen với vòng lặp if-else bình thường và phép gán biến đơn giản, hãy chuẩn bị cho đầu óc bị xoắn lại
monad không phải quái vật vũ trụ mà là một khái niệm trừu tượng kỳ lạ, có thể khiến bạn gãi đầu và nghi ngờ các lựa chọn đời mình. Thư viện thì giống như lục lọi một cửa hàng đồ cũ vơi một nửa để tìm thứ mình cần, còn tài liệu thì một nửa đọc như chữ tượng hình
Hiệu năng trong thực tế cũng có thể khiến bạn phải suy nghĩ rất lâu vì lazy evaluation làm chương trình ăn bộ nhớ nhiều hơn dự kiến và chậm đi. Việc làm cũng khó tìm, trừ khi là một công ty cực kỳ ngách dồn toàn lực vào Haskell, còn debug thì giống như mò kim đáy bể trong một đống chữ tượng hình kiểu hàm
Tôi đã dùng Scala, và thấy nó có thể đem lại điểm hay của cả hai thế giới. Có thể suy luận theo kiểu đại số, và nếu sau khi refactor mà biên dịch được thì thường nó sẽ chạy
Type inference và monad cũng hoạt động tốt, đồng thời có lợi thế từ hệ sinh thái Java. Khi mọi thứ trở nên quá khó hiểu, bạn cũng có thể phá luật và viết code gần với Java hơn. Tôi tò mò người khác nghĩ sao
Tuy vậy sbt khiến tôi phát điên, và có lẽ là phần tôi không thích nhất trong trải nghiệm phát triển
Những người quản lý và bảo trì Haskell thực sự có vẻ muốn ngôn ngữ này thân thiện với nghiên cứu, thử nghiệm và khám phá học thuật
Bản thân điều đó không sao, nhưng đến một lúc nào đó chắc chắn sẽ xung đột với lợi ích của các lập trình viên muốn dùng Haskell như một công cụ thực dụng và ổn định. Điều cần thiết có lẽ là khả năng đánh dấu các thứ mang tính thử nghiệm và tiên phong vào một track riêng. Dù là pragma hay khai báo ở cấp package, chỉ nhìn package cũng phải biết có nên kéo nó vào hay không
Như vậy các lập trình viên thiên về thực tiễn có thể áp dụng chính sách kiểu “chúng tôi chỉ dùng stable Haskell”. Cần thừa nhận động lực “Avoid success at all costs”, rằng nếu Haskell được áp dụng quá rộng thì ngôn ngữ sẽ bị quán tính kìm lại và không thể thúc đẩy các khái niệm tiên phong; nhưng vẫn cần một track chính thức để lập trình viên hằng ngày có thể ở trong một tập con Haskell hạn chế hơn và ổn định hơn
Java sẽ không bao giờ có được thứ như vậy. https://www.stackage.org/
Rốt cuộc, sự đơn giản phụ thuộc vào người nhìn. Ngay cả các tính năng kiểu hào nhoáng cũng có cách dùng khiến kiểu biểu đạt hơn, code an toàn hơn và thậm chí đơn giản hơn, nếu bạn đã nội hóa được cách chúng hoạt động
Bài viết khá hay. Nhưng điểm yếu là tôi chưa từng cảm thấy bị thúc ép phải dùng một tính năng kiểu mới mẻ, hào nhoáng nào đó nếu mình không muốn
Nếu không thích API HTTP ở cấp kiểu của Servant, có thể hạ xuống một tầng và dùng warp. Các thư viện hiểu rằng các kiểu quá phức tạp có thể trở thành cái bẫy, nên chúng thường được phân tầng theo kiểu này. Vẫn cần trực giác để biết nên đi xa đến đâu, và quá trình đó cũng bao gồm cả sai lầm
Tôi đã đọc tài liệu Servant, nhưng hiển nhiên nó giả định mức hiểu biết về Haskell nhiều hơn những gì tôi có
Bài này thật sự chạm đúng cảm giác của tôi. Tôi đã dùng Haskell khoảng 1,5 năm trong một ứng dụng khá mang tính công nghiệp, và trước đó cũng có kha khá trải nghiệm như https://github.com/mattgreen/hython
Trong 20 năm sự nghiệp, đã lâu rồi tôi mới phải học nhiều đến vậy; đó là kết quả của việc miền bài toán và ngôn ngữ cộng lại. Vừa phấn khích vừa mệt mỏi, và cũng có thể là một khối lượng khá lớn để gánh cùng với đời sống gia đình bận rộn
Dù vậy ngôn ngữ này rất xuất sắc. Quản lý của tôi thường khuyên dùng nó theo kiểu top-down, nghĩa là vì sự linh hoạt của Haskell truyền tải ý định phát triển rất tốt, hãy suy nghĩ kỹ xem mã nên được đọc như thế nào rồi bắt đầu từ đó. Đây là một thay đổi tư duy lớn so với việc gõ đi gõ lại
functiontrong hầu hết ngôn ngữ khiến não chuyển sang chế độ tiết kiệm năng lượng, và nó thật sự có cảm giác được thiết kế để thân thiện với người viếtNhưng ngay cả khi xử lý các effect được kiểm soát bằng monad, cú pháp vẫn khó đọc lướt. Có lẽ là vì một dòng có thể trở nên quá đặc. Tôi rất nhớ cơ chế trả về sớm, và cũng nhớ LSP tuyệt vời của Rust. Haskell gần đây còn mất cả tính năng điền pattern match do các thay đổi nội bộ ở bản 9.x; việc chồng monad vẫn khiến tôi ghét và tôi thường làm sai. Thời gian biên dịch có thể rất khắc nghiệt, đặc biệt khi gặp thư viện lens
Tôi cũng không thích mặc định đánh giá lười. Cộng đồng ở mức nào đó cũng đã thừa nhận rằng vì mặc định này, chương trình Haskell dễ bị rò rỉ bộ nhớ dạng space leak hơn nhiều, và trong nhiều chương trình điều đó có thể không bị phát hiện trong khá lâu. Với tư cách một lập trình viên hệ thống, điều này khiến tôi muốn hét lên
Dù vậy cộng đồng này là một trong những nhóm lập trình viên mạnh nhất mà tôi từng thấy. Tôi không muốn cứ nói theo meme rằng họ thông minh, mà điểm lớn là họ thật sự suy nghĩ rất sâu và đẩy mọi thứ tiến lên. Trong miền của chúng tôi là phân tích chương trình, Haskell hợp như găng tay, nhưng ở các lĩnh vực khác tôi vẫn hơi thận trọng. Về cơ bản tôi vẫn khát một ngôn ngữ lập trình kiểu OCaml nhưng có cú pháp tốt hơn
Cũng không cần để lộ ExceptT trong interface; chỉ dùng nó nội bộ cho trả về sớm rồi để hàm trả về Either là được
Tiếc là cuối cùng nó không đạt được nhiều traction
Việc tích hợp lập trình hướng đối tượng và lập trình hàm tốt hơn OCaml, và mã OCaml theo idiom cũng đủ tương tự để dễ chuyển sang bằng một phép biến đổi đơn giản