30

我很难理解在我的代码中何时使用和何时不使用 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 = ...

(显然,这是一个愚蠢的、不完整的例子)。

但这对于一点用处来说是很多的,不是吗?为什么我不应该做一些简单的事情,只定义函数而不定义新的数据类型和类型类(及其实例)。

这个例子太简单了,但实际上我在 github 上浏览 Haskell 代码时经常看到类似的东西(新数据类型+类型类+实例),而不仅仅是定义函数。

那么,什么时候应该创建新的数据类型、类型类等,什么时候应该使用函数?

谢谢。

4

2 回答 2

48

为什么我不应该做一些简单的事情,只定义函数而不定义新的数据类型和类型类(及其实例)。

为什么确实如此?你可以定义:

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

人们一直在滥用类型类。这并不意味着它是惯用的。

为了回答您更一般的问题,以下是一些关于何时使用类型类以及何时不使用它们的经验法则:

在以下情况下使用类型类:

  • 每个给定类型只有一个正确的行为

  • 类型类具有所有实例必须满足的相关方程(即“定律”)

在以下情况下不要使用类型类:

  • 您正在尝试命名事物。这就是模块和命名空间的用途。

  • 如果不查看实例的源代码,使用您的类型类的人无法推断其行为方式

  • 您发现必须打开的扩展程序失控了

于 2013-06-14T02:07:16.327 回答
6

您通常可以使用数据类型而不是类型类,例如

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

当然你需要显式地传递这个值,但是如果你有多种选择(例如考虑SumProduct尽可能用Monoids 表示数字),这可能是一件好事。除了您具有或多或少与类型类相同的表现力。

于 2013-06-14T13:09:39.510 回答