11

是否可以让类型成为类型类的一部分?就像是:

class KeyTraits v where
    keyType :: *
    key :: v -> keyType

data TableRow = { date :: Date, metaData :: String, value :: Int }

instance KeyTraits TableRow where
    keyType = Date
    key = date

这些“类型级”函数可以在其他地方使用吗?例如:

-- automatically deduce the type for the key, from the value type, using
-- the typeclass
data MyMap v = { getMap :: (KeyTraits v) => Map (keyType) v }

我可能做错了什么,但我基本上希望能够像上面那样定义类型关系(例如,某些值可能已经有可以用作键的数据)。如果这不可能,或者很难,您能否提出一个更符合习惯的更好设计?

谢谢!

4

2 回答 2

26

看看类型族

{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE RankNTypes #-}

class KeyTraits k where
    type KeyType k :: *
    key :: v -> KeyType k

data TableRow = TableRow { date :: Date, metaData :: String, value :: Int }

instance KeyTraits TableRow where
    type KeyType TableRow = Date
    key = date

data MyMap v = MyMap { getMap :: (KeyTraits v) => Map (KeyType v) v }
于 2013-07-01T06:52:33.013 回答
11

类型族正是您要寻找的,但还有另一种实现其功能的方法,即具有功能依赖关系的多参数类型类。使用这些扩展,您的代码可能如下所示:

{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies #-}

class KeyTraits v k | v -> k where
    key :: v -> k

data TableRow = { date :: Date, metaData :: String, value :: Int }

instance KeyTraits TableRow Date where
    key = date

在这里,关联类型迁移到类型类参数,并且 和 之间的关系vk以前是隐式的,现在通过函数依赖变得显式。

这完全等同于关联类型,但 IMO 提供了更简洁的语法,尤其是在使用您的类型类的函数中。相比:

getMap :: (KeyTraits v) => Map (KeyType v) v

getMap :: (KeyTraits k v) => Map k v

当更多类型和更多类型类出现在单一类型声明中时,这一点变得更加明显。

然而,类型族似乎更受haskell社区的青睐,实际上整个扩展比MPC+FD更强大,因为类型族可以不用类型类来声明,而且还有数据族。

于 2013-07-01T09:10:26.287 回答