了解何时使用类型 类 或 GADT?

Understanding when to uses type classes or GADT's?

我试图找出类型 类 和 GADTS 之间的区别,尤其是在使用 -XMultiParamTypeClasses 扩展名时。

两者的用途似乎相似:

class MyClass a b where
  f :: a -> b -> Bool

instance MyClass String String where
  f s1 s2 = ...

instance MyClass Int Int where
  f i1 i2 = ...

data Gadt a where
  F :: String -> String -> Bool
  F2 :: Int -> Int -> Bool

到目前为止,我真正看到的唯一区别是 GADT 使函数类型接口具有灵活的数字参数:

data Gadt a where
  PassTwoArgs :: String -> String -> Gadt Bool
  PassOneArgs :: String -> Gadt Bool

myFunction :: Gadt a -> a
myFunction (PassTwoArgs s1 s2) = ...
myFunction (PassOneArgs s1) = ...

虽然使用 类 类型不容易做到这一点。

是否有任何其他差异或用例可以使用一个而不是另一个?

如果您有 class,您可以随时添加新实例。

如果您使用 GADT,您将拥有一个永远固定的数据结构。在不更改原始定义的情况下,您永远无法向其中添加新案例。但是,正如您所注意到的,它要灵活得多。

真的,它们适用于不同的用例。 类 适用于当您希望能够对许多不同的数据类型执行操作时,这些数据类型彼此之间没有任何关系。 (例如,您可以在 IntString 上执行 (==),但这些类型不是很相似。)GADT 适用于您希望拥有 一种类型的情况,但它的一些类型参数告诉你一些关于它的信息。典型示例是 GADT 表示某种编程语言中的表达式,并且您想使用 Haskell 类型系统来强制执行 其他语言的 类型系统。

class与不同的是我们在面向对象编程中使用的"classes"。 ;-) 请把所有这些想法都赶出你的大脑。

如果需要模式匹配,请使用 (G)ADT。如果您需要第三方能够实现您的界面,请使用类型类。

我的直觉是尽可能多地使用类型类;如果我绝对需要模式匹配,那么我会使用 (G)ADT。我一般不需要。