2013-06-14 5 views
24

У меня есть некоторые трудности, чтобы понять, когда вы используете и когда не используете typeclass в моем коде. Я имею в виду создать мои собственные, а не использовать уже определенные модельные стекла, конечно. К примеру (очень глупый пример), я должен делать:Должен ли я использовать класс или нет?

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 = ... 

(Очевидно, что это глупо, неполный пример).

Но это очень мало для использования, нет? Почему я не должен делать что-то простое и только определять функции без определения новых типов данных и типов (с их экземплярами).

Этот пример слишком прост, но на практике я часто вижу такие вещи (новые типы данных + типы + экземпляры), когда я просматриваю код Haskell на github вместо определения только функций.

Итак, когда я должен создавать новые типы данных, типы и т. Д. И когда следует использовать функции?

Спасибо.

ответ

40

Почему я не должен делать что-то простое и только определяющие функции без определения новых типов данных и классов типов (с их экземпляров).

Почему именно? Вы только что определите:

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 

Люди постоянно злоупотребляют типами занятий. Это не значит, что это идиоматично.

Чтобы ответить на более общий вопрос, вот некоторые эмпирические правила для того, когда использовать классы типов и когда их не использовать:

классы использования типа, если:

  • Существует только один правильное поведение в данном типе

  • класс типа имеет соответствующие уравнения (то есть «законы»), что все экземпляры должны удовлетворять

Не используйте классы типов, если:

  • Вы пытаетесь всеми пространство имен вещей. Для этого нужны модули и пространства имен.

  • Человек, использующий свой класс типа не может рассуждать о том, как он будет вести себя, не глядя на исходный код экземпляров

  • Вы находите, что расширения вы должны включить выходят из-под контроля

+0

Да! Это очень полный ответ, спасибо вам большое! Ваш «не использовать классы типов, если ...» будет особенно полезен для выбора хорошего способа сделать что-то. – vildric

+1

Я бы добавил, что «не используйте typeclasses только для одного метода», хотя это не совсем жесткое правило, больше похоже на общий намек. – MathematicalOrchid

+2

@MathematicsOrchid Это своего рода часть правила «законов потребности», поскольку у вас редко будут законы для класса типа только с одним методом (за исключением чего-то вроде «SemiGroup», где у вас есть закон ассоциативности) –

5

Вы можете часто использовать тип данных вместо типа-типа, например

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

Конечно, вы должны передать это значение в явном виде, но это может быть хорошо, если у вас есть несколько вариантов (например, думать о Sum и Product как возможные Monoid с для чисел). За исключением того, что у вас более или менее такая же выразительность, как и для типа-класса.

+2

Я не адвуотер, но. , , этот ответ на самом деле не отвечает на вопрос ИМХО. OP спрашивает, когда следует использовать классы. Этот ответ упоминает альтернативу классам типов, но не говорит, когда использовать эту альтернативу. (Во всяком случае, кажется, что * предполагают * понимание того, когда классные классы имеют смысл, и предлагает альтернативу, которая имеет смысл во многих подобных случаях.) – ruakh

Смежные вопросы