Sự khác biệt giữa các đặc điểm trong Rust và typeclass trong Haskell là gì?


157

Đặc điểm ở Rust dường như ít nhất bề ngoài tương tự như typeclasses trong Haskell, người tuy nhiên tôi đã nhìn thấy viết rằng có một số khác biệt giữa chúng. Tôi đã tự hỏi chính xác những khác biệt này là gì.


8
Tôi không biết nhiều về Rust. Nhưng các vấp ngã phổ biến cho các công nghệ tương tự trong các ngôn ngữ khác là các loại cao hơn (ví dụ: các đặc điểm có thể vượt quá các loại tham số, nhưng không phải là tham số của chúng?) Và đa hình loại trả về (ví dụ: một loại tính trạng có thể xuất hiện trong kết quả của hàm, nhưng không phải ở bất kỳ đâu trong các đối số?). Một ví dụ về cái trước trong Haskell là class Functor f where fmap :: (a -> b) -> (f a -> f b); một ví dụ về sau này là class Bounded a where maxBound :: a.
Daniel Wagner

4
GHC cũng hỗ trợ các lớp loại đa tham số (nghĩa là các đặc điểm liên quan đến một số loại) và các phụ thuộc chức năng, mặc dù đây không phải là một phần của đặc tả Haskell chính thức. Đánh giá từ cú pháp Rust được đề xuất tại liên kết của bạn, nó chỉ có thể hỗ trợ các đặc điểm khác nhau trên một loại tại một thời điểm, mặc dù phán đoán đó một lần nữa không dựa trên kinh nghiệm sâu sắc.
Daniel Wagner

4
@DanielWagner Dạng đa hình kiểu trả về tồn tại (ví dụ std::default) và các đặc điểm đa tham số sắp xếp công việc (bao gồm cả sự tương tự của các phụ thuộc chức năng), mặc dù AFAIK cần phải làm việc xung quanh tham số đầu tiên được đặc quyền. Không có HKT tuy nhiên. Họ đang ở trong danh sách mong muốn trong tương lai xa nhưng chưa đến lúc nào.

4
sự khác biệt khác là điều trị các trường hợp mồ côi. Rust cố gắng để có các quy tắc kết hợp chặt chẽ hơn về nơi có thể viết một hàm ý mới cho một đặc điểm. Xem cuộc thảo luận này để biết thêm chi tiết (cụ thể ở đây )
Paolo Falabella

1
Rust hỗ trợ các loại liên quan và ràng buộc bình đẳng ngay bây giờ, mặc dù chúng không mạnh như các họ kiểu của Haskell. Nó cũng có các kiểu tồn tại thông qua các đối tượng đặc điểm .
Tiên nữ Lambda

Câu trả lời:


60

Ở cấp độ cơ bản, không có nhiều khác biệt, nhưng chúng vẫn ở đó.

Haskell mô tả các hàm hoặc giá trị được xác định trong một kiểu chữ là 'phương thức', giống như các đặc điểm mô tả các phương thức OOP trong các đối tượng mà chúng kèm theo. Tuy nhiên, Haskell xử lý các vấn đề này theo cách khác, coi chúng là các giá trị riêng lẻ thay vì ghim chúng vào một đối tượng như OOP sẽ khiến người ta phải làm. Đây là về sự khác biệt cấp độ bề mặt rõ ràng nhất có.

Một điều mà Rust không thể làm trong một thời gian là những đặc điểm đánh máy bậc cao , chẳng hạn như tai tiếng Functorvà kiểu chữ Monad.

Điều này có nghĩa là các đặc điểm của Rust chỉ có thể mô tả những gì thường được gọi là "loại cụ thể", nói cách khác, một đặc điểm không có đối số chung. Haskell ngay từ đầu có thể tạo ra các kiểu chữ bậc cao sử dụng các kiểu tương tự như cách các hàm bậc cao hơn sử dụng các hàm khác: sử dụng một để mô tả một kiểu khác. Trong một khoảng thời gian điều này là không thể ở Rust, nhưng vì các mục liên quan đã được triển khai, những đặc điểm như vậy đã trở nên phổ biến và thành ngữ.

Vì vậy, nếu chúng ta bỏ qua các tiện ích mở rộng, chúng không hoàn toàn giống nhau, nhưng mỗi cái có thể gần đúng những gì người khác có thể làm.

Cũng có thể đề cập, như đã nói trong các bình luận, GHC (trình biên dịch chính của Haskell) hỗ trợ các tùy chọn khác cho kiểu chữ, bao gồm nhiều kiểu chữ (nghĩa là nhiều loại liên quan) và phụ thuộc chức năng , một tùy chọn đáng yêu cho phép tính toán mức độ loại và dẫn đến loại gia đình . Theo hiểu biết của tôi, Rust không có funDeps hay loại gia đình, mặc dù nó có thể trong tương lai.

Nhìn chung, các đặc điểm và kiểu chữ có sự khác biệt cơ bản, do cách chúng tương tác, khiến chúng hành động và có vẻ khá giống nhau cuối cùng.


† A nice bài viết về typeclasses Haskell (bao gồm những người cao hơn, đánh máy) có thể được tìm thấy ở đây , và Rust bởi Ví dụ chương về những đặc điểm có thể được tìm thấy ở đây


1
Rust vẫn không có bất kỳ hình thức loại cao hơn. "Khét tiếng" cần biện minh. Functor rất phổ biến và hữu ích như một khái niệm. Các loại gia đình giống như các loại liên quan. Các phụ thuộc chức năng về cơ bản là dư thừa với các loại liên quan (bao gồm trong Haskell). Điều Rust thiếu wrt. fundeps là chú thích tiêm. Bạn có nó ngược, các đặc điểm của Rust và các lớp loại của Haskell khác nhau ở bề mặt nhưng nhiều khác biệt bốc hơi khi bạn nhìn bên dưới. Sự khác biệt chủ yếu vẫn thuộc về các lĩnh vực khác nhau mà các ngôn ngữ hoạt động.
Centril

Các mặt hàng liên kết bây giờ được coi là idomatic trong nhiều trường hợp, phải không?
Vaelus

@Vaelus Bạn đúng rồi. Câu trả lời này nên được cập nhật một chút. Chỉnh sửa ngay.
AJFarmar

19

Tôi nghĩ rằng các câu trả lời hiện tại bỏ qua những khác biệt cơ bản nhất giữa các đặc điểm của Rust và các lớp loại Haskell. Những khác biệt này có liên quan đến cách các đặc điểm có liên quan đến các cấu trúc ngôn ngữ hướng đối tượng. Để biết thông tin về điều này, xem cuốn sách Rust .

  1. Một tuyên bố đặc điểm tạo ra một loại tính trạng . Điều này có nghĩa là bạn có thể khai báo các biến có kiểu như vậy (hay đúng hơn là các tham chiếu của loại). Bạn cũng có thể sử dụng các kiểu tính trạng làm tham số trên hàm, trường cấu trúc và kiểu khởi tạo tham số kiểu.

    Một biến tham chiếu đặc điểm có thể trong thời gian chạy chứa các đối tượng thuộc các loại khác nhau, miễn là kiểu thời gian chạy của đối tượng được tham chiếu thực hiện tính trạng đó.

    // The shape variable might contain a Square or a Circle, 
    // we don't know until runtime
    let shape: &Shape = get_unknown_shape();
    
    // Might contain different kinds of shapes at the same time
    let shapes: Vec<&Shape> = get_shapes();

    Đây không phải là cách các lớp hoạt động. Loại lớp tạo không có loại , vì vậy bạn không thể khai báo các biến với tên lớp. Các lớp loại đóng vai trò là giới hạn của các tham số loại, nhưng các tham số loại phải được khởi tạo bằng một loại cụ thể, chứ không phải chính loại lớp.

    Bạn không thể có một danh sách các thứ khác nhau thuộc các loại khác nhau thực hiện cùng một loại lớp. (Thay vào đó, các kiểu tồn tại được sử dụng trong Haskell để diễn tả một điều tương tự.) Lưu ý 1

  2. Phương pháp trait có thể được gửi đi năng động . Điều này liên quan chặt chẽ đến những điều được mô tả trong phần trên.

    Công văn động có nghĩa là kiểu thời gian chạy của đối tượng một điểm tham chiếu được sử dụng để xác định phương thức nào được gọi mặc dù tham chiếu.

    let shape: &Shape = get_unknown_shape();
    
    // This calls a method, which might be Square.area or
    // Circle.area depending on the runtime type of shape
    print!("Area: {}", shape.area());

    Một lần nữa, các kiểu tồn tại được sử dụng cho điều này trong Haskell.

Tóm lại là

Đối với tôi, dường như các đặc điểm ở nhiều khía cạnh là khái niệm giống như các lớp loại. Ngoài ra, chúng có chức năng của giao diện hướng đối tượng.

Mặt khác, các loại lớp của Haskell tiên tiến hơn. Haskell có ví dụ các loại và phần mở rộng cao hơn như các lớp loại đa tham số.


Lưu ý 1 : Các phiên bản gần đây của Rust có bản cập nhật để phân biệt việc sử dụng tên tính trạng là loại và cách sử dụng tên tính trạng làm giới hạn. Trong một loại đặc điểm, tên được tiền tố bởi dyntừ khóa. Xem ví dụ câu trả lời này để biết thêm thông tin.


2
"Các lớp loại không tạo ra các loại" - Tôi nghĩ tốt nhất nên hiểu dyn Traitlà một dạng gõ hiện sinh vì chúng liên quan đến các đặc điểm / các loại lớp. Chúng ta có thể xem xét dynmột toán tử trên giới hạn chiếu chúng thành các loại, tức là dyn : List Bound -> Type. Đưa ý tưởng này cho Haskell và liên quan đến "vì vậy bạn không thể khai báo các biến với tên lớp.", Chúng ta có thể thực hiện điều này một cách gián tiếp trong Haskell : data Dyn (c :: * -> Constraint) = forall (t :: Type). c t => D t. Đã xác định điều này, chúng tôi có thể làm việc với [D True, D "abc", D 42] :: [D Show].
Centril

8

Đặc điểm của Rust là tương tự như các lớp loại của Haskell.

Sự khác biệt chính với Haskell là các đặc điểm chỉ can thiệp vào các biểu thức bằng ký hiệu dấu chấm, tức là có dạng a.foo (b).

Các lớp loại Haskell mở rộng đến các loại bậc cao hơn. Các đặc điểm của Rust chỉ không hỗ trợ các loại thứ tự cao hơn vì chúng bị thiếu trong toàn bộ ngôn ngữ, nghĩa là nó không phải là một sự khác biệt về mặt triết học giữa các đặc điểm và các loại loại


1
Các đặc điểm trong Rust không "chỉ can thiệp vào các biểu thức bằng ký hiệu dấu chấm". Ví dụ, hãy xem xét Defaultđặc điểm không có phương thức, chỉ có các hàm không liên quan đến phương thức.
Centril
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.