Thiết kế quy mô lớn ở Haskell? [đóng cửa]


565

Một cách tốt để thiết kế / cấu trúc các chương trình chức năng lớn, đặc biệt là trong Haskell là gì?

Tôi đã trải qua một loạt các hướng dẫn (Viết cho mình một Đề án là sở thích của tôi, với Real World Haskell một giây) - nhưng hầu hết các chương trình đều tương đối nhỏ và đơn mục đích. Ngoài ra, tôi không coi một số trong số chúng là đặc biệt thanh lịch (ví dụ: các bảng tra cứu rộng lớn trong WYAS).

Bây giờ tôi muốn viết các chương trình lớn hơn, với nhiều phần chuyển động hơn - thu thập dữ liệu từ nhiều nguồn khác nhau, làm sạch nó, xử lý nó theo nhiều cách khác nhau, hiển thị nó trong giao diện người dùng, duy trì nó, giao tiếp qua mạng, v.v. một cấu trúc tốt nhất như vậy để dễ đọc, có thể duy trì và thích ứng với các yêu cầu thay đổi?

Có một tài liệu khá lớn giải quyết những câu hỏi này cho các chương trình mệnh lệnh hướng đối tượng lớn. Các ý tưởng như MVC, các mẫu thiết kế, v.v. là những quy định hợp lý để hiện thực hóa các mục tiêu rộng lớn như phân tách các mối quan tâm và tái sử dụng theo kiểu OO. Ngoài ra, các ngôn ngữ mệnh lệnh mới hơn cho vay theo kiểu 'thiết kế khi bạn phát triển', theo quan điểm mới của tôi, Haskell có vẻ ít phù hợp hơn.

Có một tài liệu tương đương cho Haskell? Làm thế nào sở thú của các cấu trúc điều khiển kỳ lạ có sẵn trong lập trình chức năng (đơn nguyên, mũi tên, ứng dụng, v.v.) được sử dụng tốt nhất cho mục đích này? Những thực hành tốt nhất bạn có thể đề nghị?

Cảm ơn!

EDIT (đây là phần tiếp theo câu trả lời của Don Stewart):

@dons đã đề cập: "Monads nắm bắt các thiết kế kiến ​​trúc quan trọng trong các loại."

Tôi đoán câu hỏi của tôi là: làm thế nào người ta nên nghĩ về các thiết kế kiến ​​trúc quan trọng trong một ngôn ngữ chức năng thuần túy?

Xem xét ví dụ về một số luồng dữ liệu và một số bước xử lý. Tôi có thể viết các trình phân tích cú pháp mô đun cho các luồng dữ liệu vào một tập hợp các cấu trúc dữ liệu và tôi có thể thực hiện mỗi bước xử lý như một hàm thuần túy. Các bước xử lý cần thiết cho một phần dữ liệu sẽ phụ thuộc vào giá trị của nó và các phần khác. Một số bước nên được theo sau bởi các hiệu ứng phụ như cập nhật GUI hoặc truy vấn cơ sở dữ liệu.

Cách 'đúng' để buộc dữ liệu và các bước phân tích cú pháp theo cách hay? Người ta có thể viết một hàm lớn thực hiện đúng các loại dữ liệu khác nhau. Hoặc người ta có thể sử dụng một đơn nguyên để theo dõi những gì đã được xử lý cho đến nay và mỗi bước xử lý có được bất cứ thứ gì nó cần tiếp theo từ trạng thái đơn nguyên. Hoặc người ta có thể viết phần lớn các chương trình riêng biệt và gửi tin nhắn xung quanh (Tôi không thích tùy chọn này).

Các slide mà anh ta liên kết có một viên đạn Things Things Need: "Thành ngữ cho thiết kế ánh xạ vào các loại / hàm / lớp / monads". Các thành ngữ là gì? :)


9
Tôi nghĩ ý tưởng cốt lõi khi viết các chương trình lớn bằng ngôn ngữ chức năng là các mô-đun nhỏ, chuyên biệt và không trạng thái giao tiếp qua tin nhắn . Tất nhiên bạn phải giả vờ một chút vì một chương trình thực sự cần trạng thái. Tôi nghĩ rằng đây là nơi F # tỏa sáng trên Haskell.
ChaosPandion

18
@Chaos nhưng chỉ có Haskell thi hành trạng thái không trạng thái theo mặc định. Bạn không có lựa chọn nào khác và phải làm việc chăm chỉ để giới thiệu trạng thái (để phá vỡ thành phần) trong Haskell :-)
Don Stewart

7
@ChaosPandion: Về lý thuyết, tôi không đồng ý. Chắc chắn, trong một ngôn ngữ bắt buộc (hoặc một ngôn ngữ chức năng được thiết kế xoay quanh việc truyền thông điệp), đó rất có thể là những gì tôi sẽ làm. Nhưng Haskell có nhiều cách khác để đối phó với nhà nước, và có lẽ họ cho phép tôi giữ nhiều lợi ích 'thuần túy' hơn.
Dan

1
Tôi đã viết một chút về điều này trong phần "Nguyên tắc thiết kế" trong tài liệu này: Community.haskell.org/~ndm/doads/
Kẻ

5
@JonHarrop đừng quên rằng mặc dù MLOC là một số liệu tốt khi bạn so sánh các dự án với các ngôn ngữ tương tự, nhưng nó không có ý nghĩa gì khi so sánh giữa các ngôn ngữ, đặc biệt là với các ngôn ngữ như Haskell, nơi sử dụng lại mã và mô đun hóa dễ dàng và an toàn hơn nhiều so với một số ngôn ngữ ngoài kia
Tair

Câu trả lời:


519

Tôi nói một chút về điều này trong Kỹ thuật các dự án lớn ở Haskell và trong Thiết kế và triển khai XMonad. Kỹ thuật trong lớn là về quản lý phức tạp. Các cơ chế cấu trúc mã chính trong Haskell để quản lý độ phức tạp là:

Hệ thống loại

  • Sử dụng hệ thống loại để thực thi trừu tượng, đơn giản hóa các tương tác.
  • Thực thi các bất biến chính thông qua các loại
    • (ví dụ: các giá trị nhất định không thể thoát khỏi một số phạm vi)
    • Mã nhất định đó không có IO, không chạm vào đĩa
  • Thực thi an toàn: ngoại lệ được kiểm tra (Có thể / Hoặc), tránh trộn lẫn các khái niệm (Word, Int, Địa chỉ)
  • Các cấu trúc dữ liệu tốt (như khóa kéo) có thể làm cho một số lớp kiểm tra không cần thiết, vì chúng loại trừ các lỗi trong giới hạn tĩnh.

Trình hồ sơ

  • Cung cấp bằng chứng khách quan về hồ sơ heap và thời gian của chương trình của bạn.
  • Hồ sơ heap, đặc biệt, là cách tốt nhất để đảm bảo không sử dụng bộ nhớ không cần thiết.

Độ tinh khiết

  • Giảm độ phức tạp đáng kể bằng cách loại bỏ trạng thái. Hoàn toàn quy mô chức năng mã, bởi vì nó là thành phần. Tất cả những gì bạn cần là loại để xác định cách sử dụng một số mã - nó sẽ không bị phá vỡ một cách bí ẩn khi bạn thay đổi một số phần khác của chương trình.
  • Sử dụng nhiều lập trình kiểu "mô hình / khung nhìn / bộ điều khiển": phân tích dữ liệu ngoài càng sớm càng tốt thành các cấu trúc dữ liệu chức năng thuần túy, hoạt động trên các cấu trúc đó, sau đó khi tất cả công việc được thực hiện, kết xuất / xóa / tuần tự hóa. Giữ hầu hết mã của bạn thuần túy

Kiểm tra

  • QuickCheck + Bảo hiểm mã Haskell, để đảm bảo bạn đang kiểm tra những thứ bạn không thể kiểm tra với các loại.
  • GHC + RTS là tuyệt vời để xem nếu bạn dành quá nhiều thời gian để làm GC.
  • QuickCheck cũng có thể giúp bạn xác định các API sạch, trực giao cho các mô-đun của bạn. Nếu các thuộc tính của mã của bạn khó phát biểu, có lẽ chúng quá phức tạp. Tiếp tục tái cấu trúc cho đến khi bạn có một tập hợp các thuộc tính rõ ràng có thể kiểm tra mã của bạn, nó có thể kết hợp tốt. Sau đó, mã có thể được thiết kế tốt quá.

Monads cho cấu trúc

  • Monads nắm bắt các thiết kế kiến ​​trúc quan trọng theo loại (mã này truy cập phần cứng, mã này là phiên người dùng đơn, v.v.)
  • Ví dụ, đơn vị X trong xmonad, nắm bắt chính xác thiết kế cho trạng thái hiển thị với các thành phần nào của hệ thống.

Loại lớp và kiểu tồn tại

  • Sử dụng các lớp loại để cung cấp sự trừu tượng: ẩn các triển khai đằng sau các giao diện đa hình.

Đồng thời và song song

  • Lẻn parvào chương trình của bạn để đánh bại các đối thủ cạnh tranh song song dễ dàng, có thể kết hợp.

Cấu trúc lại

  • Bạn có thể tái cấu trúc trong Haskell rất nhiều . Các loại đảm bảo thay đổi quy mô lớn của bạn sẽ an toàn, nếu bạn sử dụng các loại một cách khôn ngoan. Điều này sẽ giúp quy mô codebase của bạn. Hãy chắc chắn rằng cấu trúc lại của bạn sẽ gây ra lỗi loại cho đến khi hoàn thành.

Sử dụng FFI một cách khôn ngoan

  • FFI làm cho việc chơi với mã nước ngoài dễ dàng hơn, nhưng mã nước ngoài đó có thể nguy hiểm.
  • Hãy rất cẩn thận trong các giả định về hình dạng của dữ liệu được trả về.

Lập trình meta

  • Một chút của Mẫu Haskell hoặc thuốc generic có thể loại bỏ bản tóm tắt.

Đóng gói và phân phối

  • Sử dụng Cabal. Đừng cuộn hệ thống xây dựng của riêng bạn. (EDIT: Thật ra bạn có thể muốn sử dụng Stack ngay bây giờ để bắt đầu.).
  • Sử dụng Haddock cho các tài liệu API tốt
  • Các công cụ như graphmod có thể hiển thị các cấu trúc mô-đun của bạn.
  • Dựa vào các phiên bản Haskell của các thư viện và công cụ, nếu có thể. Đó là một cơ sở ổn định. (EDIT: Một lần nữa, những ngày này bạn có thể muốn sử dụng Stack để có được cơ sở ổn định và chạy.)

Cảnh báo

  • Sử dụng -Wallđể giữ cho mã của bạn sạch mùi. Bạn cũng có thể nhìn vào Agda, Isabelle hoặc Catch để đảm bảo hơn. Để kiểm tra giống như xơ vải, hãy xem hlint tuyệt vời , sẽ đề xuất cải tiến.

Với tất cả các công cụ này, bạn có thể xử lý sự phức tạp, loại bỏ càng nhiều tương tác giữa các thành phần càng tốt. Lý tưởng nhất, bạn có một cơ sở mã nguyên chất rất lớn, rất dễ bảo trì, vì nó là thành phần. Điều đó không phải lúc nào cũng có thể, nhưng nó đáng để hướng tới.

Nói chung: phân tách các đơn vị logic của hệ thống của bạn thành các thành phần minh bạch tham chiếu nhỏ nhất có thể, sau đó triển khai chúng trong các mô-đun. Môi trường toàn cầu hoặc cục bộ cho các bộ thành phần (hoặc bên trong các thành phần) có thể được ánh xạ tới các đơn nguyên. Sử dụng các kiểu dữ liệu đại số để mô tả các cấu trúc dữ liệu cốt lõi. Chia sẻ những định nghĩa rộng rãi.


8
Cảm ơn Don, câu trả lời của bạn rất tuyệt vời - đây đều là những hướng dẫn có giá trị và tôi sẽ đề cập đến chúng thường xuyên. Tôi đoán rằng câu hỏi của tôi xảy ra một bước trước khi người ta sẽ cần tất cả điều này, mặc dù. Điều tôi thực sự muốn biết là "Thành ngữ cho thiết kế ánh xạ vào các loại / chức năng / lớp / đơn vị" ... Tôi có thể cố gắng tự phát minh, nhưng tôi hy vọng có thể có một tập hợp thực tiễn tốt nhất được chưng cất ở đâu đó - hoặc nếu không, các khuyến nghị cho mã có cấu trúc tốt để đọc một hệ thống lớn (trái ngược với, một thư viện tập trung). Tôi chỉnh sửa bài viết của mình để hỏi cùng câu hỏi này trực tiếp hơn.
Dan

6
Tôi đã thêm một số văn bản về phân rã thiết kế vào các mô-đun. Mục tiêu của bạn là xác định các chức năng liên quan đến logic thành các mô đun có giao diện minh bạch tham chiếu với các bộ phận khác của hệ thống và sử dụng các loại dữ liệu chức năng thuần túy càng sớm càng tốt, để mô hình hóa thế giới bên ngoài một cách an toàn. Tài liệu thiết kế xmonad bao gồm rất nhiều điều này: xmonad.wordpress.com/2009/09/09/ trên
Don Stewart

3
Tôi đã cố tải xuống các slide từ Engineering Large Project trong Haskell talk, nhưng liên kết dường như bị phá vỡ. Đây là một công việc: galois.com/~dons/talks/dons-londonhug-decade.pdf
mik01aj

3
Tôi quản lý để tìm thấy liên kết tải xuống mới này: pau-za.cz/data/2/sprava.pdf
Riccardo T.

3
@Heather Mặc dù liên kết tải xuống tại trang tôi đã đề cập trong bình luận ngay trước khi không hoạt động, có vẻ như các slide vẫn có thể được xem trên scribd: scribd.com/doc/19503176/The-Design-and-Imcellenceation-of -xmonad
Riccardo T.

118

Don đã cung cấp cho bạn hầu hết các chi tiết ở trên, nhưng đây là hai xu của tôi khi thực hiện các chương trình trạng thái thực sự khó chịu như daemon hệ thống trong Haskell.

  1. Cuối cùng, bạn sống trong một ngăn xếp máy biến áp. Ở phía dưới là IO. Trên đó, mọi mô-đun chính (theo nghĩa trừu tượng, không phải ý nghĩa mô-đun trong tệp) ánh xạ trạng thái cần thiết của nó thành một lớp trong ngăn xếp đó. Vì vậy, nếu bạn có mã kết nối cơ sở dữ liệu của mình bị ẩn trong một mô-đun, bạn viết tất cả để vượt qua loại Kết nối MonadReader m => ... -> m ... và sau đó các chức năng cơ sở dữ liệu của bạn luôn có thể nhận được kết nối của chúng mà không có chức năng từ người khác các mô-đun phải nhận thức được sự tồn tại của nó. Bạn có thể kết thúc với một lớp mang kết nối cơ sở dữ liệu của bạn, một cấu hình khác của bạn, một phần ba các ngữ nghĩa và mvar khác nhau của bạn để giải quyết song song và đồng bộ hóa, một lớp khác của tệp nhật ký của bạn, v.v.

  2. Tìm ra xử lý lỗi của bạn đầu tiên . Điểm yếu lớn nhất tại thời điểm này đối với Haskell trong các hệ thống lớn hơn là rất nhiều phương pháp xử lý lỗi, bao gồm cả những phương pháp tệ hại như Có thể (sai vì bạn không thể trả lại bất kỳ thông tin nào về sự cố; luôn luôn sử dụng Hoặc thay vì Có thể trừ khi bạn thực sự chỉ có nghĩa là thiếu giá trị). Tìm hiểu làm thế nào bạn sẽ làm điều đó trước tiên và thiết lập bộ điều hợp từ các cơ chế xử lý lỗi khác nhau mà thư viện và các mã khác sử dụng vào cơ chế cuối cùng của bạn. Điều này sẽ cứu bạn một thế giới đau buồn sau này.

Phụ lục (trích từ các bình luận; nhờ Lii & liminalisht ) -
thảo luận thêm về các cách khác nhau để cắt một chương trình lớn thành các đơn nguyên trong một ngăn xếp:

Ben Kolera đưa ra một giới thiệu thực tế tuyệt vời cho chủ đề này, và Brian Hurt thảo luận về các giải pháp cho vấn đề đưa các lifthành động đơn điệu vào đơn nguyên tùy chỉnh của bạn. George Wilson cho thấy cách sử dụng mtlđể viết mã hoạt động với bất kỳ đơn nguyên nào thực hiện các kiểu chữ được yêu cầu, thay vì loại đơn nguyên tùy chỉnh của bạn. Carlo Hamalainen đã viết một số ghi chú ngắn, hữu ích tóm tắt cuộc nói chuyện của George.


5
Hai điểm tốt! Câu trả lời này có giá trị là cụ thể hợp lý, điều mà những người khác không có. Sẽ rất thú vị khi đọc thêm thảo luận về các cách khác nhau để cắt một chương trình lớn thành các đơn nguyên trong một ngăn xếp. Xin vui lòng gửi liên kết đến các bài viết như vậy nếu bạn có bất kỳ!
Lii

6
@Lii Ben Kolera đưa ra một giới thiệu thực tế tuyệt vời cho chủ đề này, và Brian Hurt thảo luận về các giải pháp cho vấn đề đưa các lifthành động đơn nguyên vào đơn nguyên tùy chỉnh của bạn. George Wilson cho thấy cách sử dụng mtlđể viết mã hoạt động với bất kỳ đơn nguyên nào thực hiện các kiểu chữ được yêu cầu, thay vì loại đơn nguyên tùy chỉnh của bạn. Carlo Hamalainen đã viết một số ghi chú ngắn, hữu ích tóm tắt cuộc nói chuyện của George.
liminalisht

Tôi đồng ý rằng các ngăn xếp máy biến áp đơn nguyên có xu hướng là nền tảng kiến ​​trúc quan trọng, nhưng tôi rất cố gắng để giữ IO ra khỏi chúng. Không phải lúc nào cũng có thể, nhưng nếu bạn nghĩ về "và sau đó" nghĩa là gì trong đơn nguyên của bạn, bạn có thể phát hiện ra rằng bạn thực sự có một sự tiếp tục hoặc tự động ở đâu đó ở phía dưới mà sau đó có thể được hiểu thành IO bởi chức năng "chạy".
Paul Johnson

Như @PaulJohnson đã chỉ ra, cách tiếp cận Monad Transformer Stack này dường như mâu thuẫn với Mẫu thiết kế ReaderT
McBear Holden 29/03/18

43

Thiết kế các chương trình lớn trong Haskell không khác với thực hiện bằng các ngôn ngữ khác. Lập trình nói chung là về việc phá vỡ vấn đề của bạn thành các phần có thể quản lý được và làm thế nào để kết hợp những vấn đề đó lại với nhau; ngôn ngữ thực hiện là ít quan trọng.

Điều đó nói rằng, trong một thiết kế lớn, thật tuyệt khi thử và tận dụng hệ thống loại để đảm bảo bạn chỉ có thể ghép các mảnh của mình lại với nhau theo cách chính xác. Điều này có thể liên quan đến các loại newtype hoặc Phantom để làm cho những thứ có vẻ giống nhau trở nên khác biệt.

Khi nói đến việc tái cấu trúc mã khi bạn thực hiện, độ tinh khiết là một lợi ích tuyệt vời, vì vậy hãy cố gắng giữ càng nhiều mã càng tốt. Mã thuần rất dễ tái cấu trúc, bởi vì nó không có tương tác ẩn với các phần khác trong chương trình của bạn.


14
Tôi thực sự thấy rằng tái cấu trúc là khá bực bội, nếu các loại dữ liệu cần phải thay đổi. Nó đòi hỏi phải sửa đổi tẻ nhạt sự phong phú của rất nhiều nhà xây dựng và khớp mẫu. (Tôi đồng ý rằng việc tái cấu trúc các hàm thuần thành các hàm thuần khác cùng loại rất dễ dàng - miễn là người ta không chạm vào các loại dữ liệu)
Dan

2
@Dan Bạn có thể thoát khỏi hoàn toàn miễn phí với những thay đổi nhỏ hơn (như chỉ thêm một trường) khi bạn sử dụng hồ sơ. Một số người có thể muốn tạo hồ sơ thành thói quen (Tôi là một trong số họ ^^ ").
MasterMastic

5
@ Ý tôi là nếu bạn thay đổi kiểu dữ liệu của hàm theo bất kỳ ngôn ngữ nào thì bạn không phải làm như vậy? Tôi không thấy một ngôn ngữ như Java hay C ++ sẽ giúp bạn như thế nào về vấn đề này. Nếu bạn nói rằng bạn có thể sử dụng một số loại giao diện phổ biến mà cả hai loại đều tuân theo thì bạn nên làm điều đó với Máy đánh chữ trong Haskell.
dấu chấm phẩy

4
@semiaon sự khác biệt cho các ngôn ngữ như Java là sự tồn tại của các công cụ hoàn thiện, được kiểm tra tốt và hoàn toàn tự động để tái cấu trúc. Nói chung các công cụ này có tích hợp trình soạn thảo tuyệt vời và lấy đi một lượng lớn công việc tẻ nhạt liên quan đến tái cấu trúc. Haskell cung cấp cho chúng ta một hệ thống loại tuyệt vời để phát hiện những thứ phải thay đổi trong tái cấu trúc, nhưng các công cụ để thực hiện tái cấu trúc đó là (hiện tại) rất hạn chế, đặc biệt là so với những gì đã có trong Java hệ sinh thái trong hơn 10 năm.
JSK

16

Tôi đã học lập trình chức năng có cấu trúc lần đầu tiên với cuốn sách này . Nó có thể không chính xác những gì bạn đang tìm kiếm, nhưng đối với người mới bắt đầu lập trình chức năng, đây có thể là một trong những bước đầu tiên tốt nhất để tìm hiểu cấu trúc các chương trình chức năng - không phụ thuộc vào quy mô. Trên tất cả các mức độ trừu tượng, thiết kế phải luôn có các cấu trúc được sắp xếp rõ ràng.

Thủ công lập trình chức năng

Thủ công lập trình chức năng

http://www.cs.kent.ac.uk/people/staff/sjt/craft2e/


11
Tuyệt vời như Craft of FP là - tôi đã học được Haskell từ nó - nó là một văn bản giới thiệu cho các lập trình viên mới bắt đầu , không phải để thiết kế các hệ thống lớn trong Haskell.
Don Stewart

3
Chà, đây là cuốn sách hay nhất tôi biết về thiết kế API và ẩn chi tiết triển khai. Với cuốn sách này, tôi đã trở thành một lập trình viên giỏi hơn trong C ++ - chỉ vì tôi đã học được những cách tốt hơn để tổ chức mã của mình. Chà, kinh nghiệm của bạn (và câu trả lời) chắc chắn tốt hơn cuốn sách này, nhưng Dan có lẽ vẫn là người mới bắt đầu ở Haskell. ( where beginner=do write $ tutorials `about` Monads)
comonad

11

Tôi hiện đang viết một cuốn sách với tiêu đề "Thiết kế và kiến ​​trúc chức năng". Nó cung cấp cho bạn một bộ đầy đủ các kỹ thuật làm thế nào để xây dựng một ứng dụng lớn bằng cách sử dụng phương pháp tiếp cận chức năng thuần túy. Nó mô tả nhiều mẫu chức năng và ý tưởng trong khi xây dựng một ứng dụng giống như 'Andromeda' của SCADA để kiểm soát tàu vũ trụ từ đầu. Ngôn ngữ chính của tôi là Haskell. Cuốn sách bao gồm:

  • Phương pháp tiếp cận mô hình kiến ​​trúc bằng sơ đồ;
  • Phân tích yêu cầu;
  • Mô hình hóa miền DSL nhúng;
  • Thiết kế và triển khai DSL bên ngoài;
  • Monads là hệ thống con có hiệu ứng;
  • Đơn nguyên miễn phí như giao diện chức năng;
  • EDSL mũi tên;
  • Đảo ngược điều khiển bằng các eDSL đơn âm miễn phí;
  • Bộ nhớ giao dịch phần mềm;
  • Ống kính;
  • Bang, Độc giả, Nhà văn, RWS, ST đơn nguyên;
  • Trạng thái không tinh khiết: IORef, MVar, STM;
  • Mô hình miền đa luồng và đồng thời;
  • GUI;
  • Khả năng áp dụng các kỹ thuật và phương pháp tiếp cận chủ đạo như UML, RẮN, GRASP;
  • Tương tác với các hệ thống con không tinh khiết.

Bạn có thể làm quen với mã cho cuốn sách ở đây và mã dự án 'Andromeda' .

Tôi hy vọng sẽ hoàn thành cuốn sách này vào cuối năm 2017. Cho đến khi điều đó xảy ra, bạn có thể đọc bài viết của tôi "Thiết kế và kiến ​​trúc trong lập trình chức năng" (Rus) tại đây .

CẬP NHẬT

Tôi đã chia sẻ cuốn sách của mình trực tuyến (5 chương đầu tiên). Xem bài đăng trên Reddit


Alexander, bạn có thể vui lòng cập nhật ghi chú này khi cuốn sách của bạn đã hoàn thành, vì vậy chúng tôi có thể theo dõi nó. Chúc mừng.
Tối đa

4
Chắc chắn rồi! Hiện tại tôi đã hoàn thành một nửa văn bản, nhưng đó là một phần ba của toàn bộ công việc. Vì vậy, hãy giữ sự quan tâm của bạn, điều này truyền cảm hứng cho tôi rất nhiều!
granina

2
Chào! Tôi đã chia sẻ cuốn sách của mình trực tuyến (chỉ 5 chương đầu tiên). Xem bài đăng trên Reddit: reddit.com/r/haskell/comments/6ck72h/ trên
granina

cảm ơn đã chia sẻ và làm việc
Tối đa

Thực sự mong này!
yêu nước

7

Bài đăng trên blog của Gabriel Kiến trúc chương trình có thể mở rộng có thể đáng được đề cập.

Các mẫu thiết kế Haskell khác với các mẫu thiết kế chính theo một cách quan trọng:

  • Kiến trúc thông thường : Kết hợp một số thành phần với nhau loại A để tạo ra một "mạng" hoặc "cấu trúc liên kết" của loại B

  • Kiến trúc Haskell : Kết hợp một số thành phần với nhau loại A để tạo ra một thành phần mới cùng loại A, không thể phân biệt tính chất từ ​​các bộ phận thay thế của nó

Nó thường gây ấn tượng với tôi rằng một kiến ​​trúc thanh lịch rõ ràng thường có xu hướng rơi ra khỏi các thư viện thể hiện cảm giác đồng nhất tốt đẹp này, theo cách từ dưới lên. Trong Haskell, điều này đặc biệt rõ ràng - các mẫu mà theo truyền thống sẽ được coi là "kiến trúc từ trên xuống" có xu hướng được chụp trong các thư viện như mvc , NetwireCloud Haskell . Điều đó có nghĩa là, tôi hy vọng câu trả lời này sẽ không được hiểu là một nỗ lực thay thế bất kỳ câu hỏi nào khác trong luồng này, chỉ là các lựa chọn cấu trúc có thể và lý tưởng nên được trừu tượng hóa trong các thư viện bởi các chuyên gia tên miền. Khó khăn thực sự trong việc xây dựng các hệ thống lớn, theo tôi, là đánh giá các thư viện này về "lòng tốt" kiến ​​trúc của họ so với tất cả các mối quan tâm thực dụng của bạn.

Như liminalisht đề cập trong các bình luận, Mẫu thiết kế thể loại là một bài viết khác của Gabriel về chủ đề này, trong một tĩnh mạch tương tự.


3
Tôi sẽ đề cập đến một bài viết khác của Gabriel Gonzalez về mẫu thiết kế thể loại . Lập luận cơ bản của ông là những gì các lập trình viên chức năng của chúng tôi nghĩ là "kiến trúc tốt" thực sự là "kiến trúc tổng hợp" - đó là thiết kế các chương trình sử dụng các vật phẩm được đảm bảo để sáng tác. Vì các luật danh mục đảm bảo rằng danh tính và tính kết hợp được bảo tồn theo thành phần, nên một kiến ​​trúc thành phần đạt được thông qua việc sử dụng các khái niệm trừu tượng mà chúng ta có một thể loại - ví dụ như các hàm thuần túy, các hành động đơn điệu, các đường ống, v.v.
liminalisht


3

Có lẽ bạn phải lùi lại một bước và nghĩ cách dịch mô tả vấn đề sang thiết kế ngay từ đầu. Vì Haskell ở mức rất cao, nó có thể nắm bắt mô tả vấn đề dưới dạng cấu trúc dữ liệu, các hành động như các thủ tục và chuyển đổi thuần túy như các hàm. Sau đó, bạn có một thiết kế. Quá trình phát triển bắt đầu khi bạn biên dịch mã này và tìm thấy các lỗi cụ thể về các trường bị thiếu, các trường hợp bị thiếu và các biến áp đơn âm bị thiếu trong mã của bạn, vì ví dụ bạn thực hiện cơ sở dữ liệu Truy cập từ thư viện cần một đơn vị trạng thái nhất định trong quy trình IO. Và voila, có chương trình. Trình biên dịch cung cấp các bản phác thảo tinh thần của bạn và cung cấp sự gắn kết cho thiết kế và phát triển.

Theo cách đó, bạn được hưởng lợi từ sự giúp đỡ của Haskell ngay từ đầu, và mã hóa là điều tự nhiên. Tôi sẽ không quan tâm để làm một cái gì đó "chức năng" hoặc "tinh khiết" hoặc đủ chung nếu những gì bạn có trong đầu là một vấn đề thông thường cụ thể. Tôi nghĩ rằng kỹ thuật quá mức là điều nguy hiểm nhất trong CNTT. Mọi thứ khác nhau khi vấn đề là tạo ra một thư viện trừu tượng một tập hợp các vấn đề liên quan.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.