2011-07-13 849 views
5

Tôi đang cố gắng để tạo ra một "kế thừa" của các lớp học kiểu đại số, như sau:-nửa nhóm/monoid/Nhóm kiểu lớp thứ bậc trong các lỗi Haskell

class Semigroup a where 
    (.*) :: a -> a -> a 
    foldr1 (.*) = foldl1 (.*) -- GHCi error: "`foldr1' is not a (visible) method of class `Semigroup'" 

class (Semigroup a) => Monoid a where 
    identity :: a 
    (.*) identity = id :: a -> a -- GHCi error: "`.*' is not a (visible) method of class `Monoid'" 

class (Monoid a) => Group a where 
    inverse :: a -> a 

Như vậy, nhóm này monoids và monoids là nửa nhóm. Tuy nhiên, tôi nhận được lỗi rằng các lớp học không thể nhìn thấy các chức năng của lớp cha mẹ của họ.

Các lỗi này gây lỗi cho tôi vì tôi giả định rằng bằng cách viết (ví dụ) class (Semigroup a) => Monoid a lớp Monoid a sẽ có thể xem hàm (.*). Và hơn nữa, loại foldr1 trong Prelude không có ràng buộc, vì vậy tôi giả định rằng foldr1 sẽ hoạt động trong ngữ cảnh này.

+0

Để làm rõ, điều tôi định làm là triển khai các tiên đề cho các nhóm semigroup, monoids và nhóm dưới dạng các lớp kiểu. Do đó, lớp 'Semigroup a' phải đi kèm với một phép toán nhị phân kết hợp' (. *) :: a -> a -> a'. Tôi đã cố gắng ám chỉ sự liên kết bằng cách sử dụng 'foldr1', nhưng đây là lần thử thứ ba của tôi, được bắt đầu bởi' (x. * Y). * Z = x. * (Y. * Z) 'và' \ xyz -> (x. * y). * z = \ xyz -> x. * (y. * z) '. Sau đó, tôi muốn lớp 'Monoid a' là một lớp con của' Subgroup a', kế thừa hoạt động nhị phân '(. *)' Và hiển thị cách nó tương tác với phần tử 'identity' (tức là, tầm thường). –

+1

Bạn đang cố gắng nêu rõ luật pháp cho '(. *)'? Bạn không thể làm điều đó trong các khai báo lớp; Tôi nghĩ rằng bạn cần phải xem xét các quy tắc viết lại để có được hiệu quả mà bạn muốn. – yatima2975

+1

@ yatima2975 Tôi nhìn lên và tôi chưa thử, nhưng trông giống như những gì tôi đang tìm kiếm. Cảm ơn rất nhiều –

Trả lời

5

Haskell không cho phép bạn khai báo (hoặc thi hành) phương trình trên các điều khoản (như nó có vẻ như bạn muốn làm). Đây là một lý do rất thực tế: chứng minh sự bình đẳng giữa các thuật ngữ tùy ý trong một ngôn ngữ lập trình phong phú như Haskell là không thể xác định. Kiểm tra một bằng chứng do con người xây dựng thường là đáng tin cậy, nhưng nó cũng hơi khó chịu khi phải viết và theo dõi các bằng chứng này trong khi lập trình.

Tuy nhiên, nếu đây là loại điều bạn muốn thực hiện thường xuyên, thì các ngôn ngữ có thể thực hiện điều này; cụm từ tìm kiếm là "loại phụ thuộc". Ví dụ, Coq và Agda có lẽ là hai ngôn ngữ được đánh máy phổ biến nhất hiện nay, và mỗi ngôn ngữ sẽ làm cho nó trở nên đơn giản để viết một kiểu sinh sống chỉ bởi các nhóm bán tốt, tuân thủ luật pháp (hoặc monoids).

4

Tôi không chắc bạn đang cố gắng làm gì.

Nếu bạn đang cố gắng cung cấp giá trị mặc định cho foldr1 trong Semigroup và giá trị mặc định cho (.*) trong Monoid, thì bạn không thể.

  • foldr1 được định nghĩa trong Prelude là một hàm phi typeclass, vì vậy bạn không thể cung cấp cho nó một định nghĩa địa phương trong Semigroup
  • (.*) là một phần của lớp Semigroup. Bạn có thể cho giá trị của nó trong Semigroup trường hợp, và bạn có thể cho một giá trị mặc định cho nó trong lớp Semigroup, nhưng bạn không thể đưa ra giá trị của nó trong lớp Monoid (hoặc Monoid trường hợp)

Nếu bạn cố gắng cung cấp giá trị mặc định cho (.*) trong Semigroup và giá trị mặc định cho identity trong Monoid, khi đó bạn đang sử dụng cú pháp sai.

Thay vì cố gắng một cái gì đó giống như

class Semigroup a where 
    (.*) :: a -> a -> a 
    (.*) = {-something-} 

hoặc

class Semigroup a where 
    (.*) :: a -> a -> a 
    x .* y = {-something-}