2013-06-14 36 views
24

Tôi có một số khó khăn để hiểu khi sử dụng và khi không sử dụng typeclass trong mã của tôi. Tôi có nghĩa là tự tạo của riêng mình và không sử dụng sử dụng đã được xác định là máy đánh chữ, tất nhiên. Ví dụ (ví dụ rất ngu ngốc), tôi nên làm:Tôi có nên sử dụng typeclasses hay không?

data Cars = Brakes | Wheels | Engine 
data Computers = Processor | RAM | HardDrive 

class Repairable a where 
    is_reparaible :: a -> Bool 

instance Repairable Cars where 
    is_repairable (Brakes) = True 
    is_repairable (Wheels) = False 
    is_repairable (Engine) = False 

instance Repairable Computers where 
    is_repairable (Processor) = False 
    is_repairable (RAM)  = False 
    is_repairable (HardDrive) = True 

checkState :: (Reparaible a) => a -> ... 
checkState a = ... 

(Rõ ràng, đây là một ví dụ ngu ngốc, không đầy đủ).

Nhưng điều này là rất nhiều cho một ít sử dụng, không? Tại sao tôi không nên làm một cái gì đó đơn giản và chỉ định nghĩa các hàm mà không định nghĩa các kiểu dữ liệu mới và các kiểu chữ (với các cá thể của chúng).

Ví dụ này quá đơn giản, nhưng trong thực tế tôi thường thấy những thứ như thế (kiểu dữ liệu mới + kiểu chữ + trường hợp) khi tôi duyệt mã Haskell trên github thay vì chỉ định nghĩa hàm.

Vì vậy, khi tôi nên tạo kiểu dữ liệu mới, typeclasses vv và khi nào tôi nên sử dụng chức năng?

Cảm ơn.

Trả lời

40

Tại sao tôi không nên làm điều gì đó đơn giản và chỉ quy định chức năng mà không cần xác định kiểu dữ liệu mới và typeclasses (với trường của họ).

Tại sao thực sự? Bạn chỉ có thể xác định:

checkState :: (a -> Bool) -> (a -> b) -> (a -> b) -> a -> b 
checkState is_repairable repairs destroy a 
    = if (is_repairable a) then repairs a else destroy a 

Mọi người thường xuyên sử dụng lớp loại sai. Nó không có nghĩa là nó thành ngữ.

Để trả lời câu hỏi tổng quát hơn của bạn, sau đây là một số quy tắc của ngón tay cái khi sử dụng các lớp học kiểu và khi không sử dụng chúng:

lớp Sử dụng loại nếu:

  • Chỉ có một hành vi đúng mỗi loại nhất định

    phương trình
  • lớp loại đã liên kết (tức là "luật") mà tất cả các trường phải có đủ

Không sử dụng các lớp học kiểu nếu:

  • Bạn đang cố gắng chỉ namespace thứ. Đó là những gì mô-đun và không gian tên được cho.

  • Một người sử dụng lớp loại của bạn không thể lý luận về cách nó sẽ hoạt động mà không nhìn vào mã nguồn của các trường hợp

  • Bạn thấy rằng các phần mở rộng, bạn phải bật đang nhận được ngoài tầm kiểm soát

+0

Vâng! Đây là một câu trả lời rất hoàn chỉnh, cảm ơn bạn rất nhiều! "Bạn không sử dụng các lớp loại nếu ..." sẽ hữu ích để chọn cách tốt để làm điều gì đó. – vildric

+1

Tôi sẽ thêm vào điều này "không sử dụng typeclasses chỉ cho một phương pháp", mặc dù đây không phải là một quy tắc hoàn toàn cứng nhắc, giống như một gợi ý chung. – MathematicalOrchid

+2

@MathematicalOrchid Đó là một phần của quy tắc "nhu cầu luật" vì bạn hiếm khi có luật cho một loại lớp chỉ với một phương pháp (ngoại trừ một cái gì đó như 'SemiGroup', nơi bạn có luật liên kết) –

5

Bạn thường có thể sử dụng loại dữ liệu thay vì loại lớp, ví dụ:

data Repairable a = Repairable 
    { getRepairable :: a 
    , isRepairable :: Bool 
    , canBeRepairedWith :: [Tool] -> Bool -- just to give an example of a function 
    } 

Tất nhiên bạn cần phải vượt qua giá trị này một cách rõ ràng, nhưng điều này có thể là một điều tốt nếu bạn có nhiều lựa chọn (ví dụ nghĩ đến SumProduct càng tốt Monoid s cho số). Ngoại trừ việc bạn có nhiều hay ít tính biểu cảm giống như đối với một loại lớp.

+2

Tôi không phải là downvoter, nhưng. . . câu trả lời này không thực sự trả lời câu hỏi IMHO. OP yêu cầu khi sử dụng typeclasses. Câu trả lời này đề cập đến một cách thay thế cho typeclasses, nhưng không nói khi nào nên sử dụng giải pháp thay thế đó. (Nếu có bất cứ điều gì, có vẻ như * giả định * một sự hiểu biết về thời điểm typeclasses có ý nghĩa, và cung cấp một sự thay thế có ý nghĩa trong nhiều trường hợp tương tự.) – ruakh

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