2014-10-07 16 views
7

Hầu hết mã Haskell tôi thấy sử dụng các cấu trúc trực tiếp như danh sách và cây cối. Ví dụ, người ta thường cho một Haskeller viết:Tương đương với các module của OCaml trong Haskell là gì?

fillRect :: Color → Bounds → Image → Image 

mẫu đó có một vấn đề: nếu sau này các lập trình viên quyết định sửa đổi định nghĩa về "Hình ảnh", hoặc sử dụng một cấu trúc dữ liệu, sau đó ông sẽ phải refactor mỗi đoạn mã duy nhất bằng cách sử dụng nó. Trong OCaml, bạn có thể chỉ cần sử dụng một mô-đun xác định một giao diện cho một hình ảnh, và sau đó quyết định khi triển khai cụ thể sau này.

Thay thế Haskell cho mô-đun OCaml là gì?

+0

Chữ ký loại đó có nghĩa là 'fillRect' sử dụng (hoặc thậm chí có quyền truy cập vào) chi tiết triển khai của loại' Hình ảnh' như thế nào? Làm thế nào bạn sẽ viết chữ ký đó khác nhau trong OCaml (khác với sự khác biệt cú pháp rõ ràng và các quy ước đặt tên khác nhau)? – sepp2k

+6

[Đây là tương tự Haskell] (http://lukepalmer.wordpress.com/2010/01/24/haskell-antipattern-existential-typeclass/) của những gì bạn mô tả. Nó không mạnh bằng các mô-đun Ocaml (ít nhất, không có nhiều phần mở rộng), nhưng nó bao gồm các trường hợp sử dụng phổ biến nhất. Chỉ cần ghi lại các hàm đa hình trên loại hỗ trợ các hoạt động đó. –

+2

Ba lô là một nỗ lực để có được một số hình thức mô-đun vào Haskell - http://plv.mpi-sws.org/backpack/ – nlucaroni

Trả lời

10

Có một số lựa chọn thay thế; không chính xác khớp với các mô-đun ML, nhưng mỗi một số khía cạnh.

  • Đa hình tham số. Thay vì tham số hóa mô-đun của bạn và chức năng fillRect trong đó trên Image, bạn tham số trừu tượng Image loại -constructor trên thứ gì đó chỉ định "loại" hình ảnh cụ thể. Vì vậy, đó sẽ là chữ ký giống như

    fillRect_ppm :: ImageImplemetation i => Colour -> Bounds -> Image i -> Image i 
    

    nơi ImageImplemetation là một loại lớp chỉ định chức năng chuyển đổi và/hoặc phụ trợ.
    Với giải pháp như vậy, bạn có thể không thực sự thay thế loại Image hoàn toàn, nhưng bạn có thể tự tạo loại linh hoạt tùy ý. Có thể, tất cả các loại cụ thể mà bạn sẽ sử dụng cho Image sẽ thực sự chia sẻ một số trường, vì vậy tốt hơn là không làm cho nó linh hoạt hơn cần thiết: các trường hợp khác nhau của ImageImplemetation chỉ cần triển khai khác nhau giữa chúng. Nếu việc triển khai rất giống nhau, có lẽ bạn muốn tham số chỉ trên một số chi tiết như không gian màu.
    Tất nhiên bạn cần lập kế hoạch trước một chút với giải pháp này, nhưng chỉ cho một giao diện chung. Bạn vẫn có thể đặt bất kỳ loại làm đối số sau, miễn là bạn xác định các trường hợp cần thiết.

  • Tương tự (và có thể trộn), bạn chỉ có thể có loại lớp cho loại có thể chứa dữ liệu hình ảnh.

    fillRect_tcl :: Image img => Colour -> Bounds -> img -> img 
    

    Lớp Image sẽ trực tiếp xác định một số nguyên thủy như thế nào để vẽ đường thẳng, và fillRect_tcl sẽ sử dụng những trong việc thực hiện của nó. Tốt vì fillRect_tcl hoạt động ngay với bất kỳ loại nào như vậy. Có gì là xấu một chút là lớp Image sẽ cần phải được khá lúng túng lớn (đó là ưa thích để sử dụng các loại lớp cho "công cụ toán học" với luật đơn giản và rất rõ ràng).

    • Có lẽ lớp thậm chí có thể có hình chữ nhật như một phương pháp:

      class Image img where 
          ... 
          fillRect_tcm :: Colour -> Bounds -> img -> img 
          ... 
      

      không quá tốt đẹp là, bạn sẽ cần phải hoàn toàn tái xác định phương pháp mà đối với bất kỳ img dụ.

  • hệ thống mô-đun của Haskell không thể làm được rất nhiều, nhưng vẫn còn đó là đôi khi đủ để giúp bạn tiết kiệm từ refactoring mọi thứ. Ví dụ, nếu Image xuất thân từ một mô-đun Data.Image, bạn có thể làm

    import qualified Data.Image as IM 
    
    fillRect_qfi :: Colour -> Bounds -> IM.Image -> IM.Image 
    

    và sử dụng tất cả các chức năng được xác định trong mô-đun đó, cũng bởi vòng loại. Nếu tại một số thời điểm bạn quyết định chuyển đổi triển khai, bạn chỉ có thể thay đổi quá trình nhập.
    Tất nhiên điều này không tốt cho việc chuyển đổi giữa các loại một cách thường xuyên, nhưng khá ổn cho những thay đổi một lần.

Khá phù hợp với ví dụ của bạn: diagrams sử dụng cả hai điểm đầu tiên; ví dụ. rect sử dụng lớp TrailLike để triển khai nguyên thủy của nó và lớp này bao gồm sơ đồ "cuối cùng" loại QDiagram, được tham số hóa trên chương trình phụ trợ mà bạn sẽ sử dụng để hiển thị.

Các vấn đề liên quan