Haskell: могут ли типы типов определять типы (черты типа ala)
Возможно ли, чтобы тип был частью класса? Что-то вроде:
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 }
Я могу делать что-то совершенно неправильное, но я в основном хочу, чтобы определить отношения типа, такие как выше (например, некоторые значения уже могут иметь данные, которые можно использовать в качестве ключа). Если это невозможно или сложно, можете ли вы предложить лучший дизайн, более идиоматический?
Спасибо!
Ответы
Ответ 1
Взгляните на типы семейств.
{-# 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 }
Ответ 2
Типы типов - это именно то, что вы ищете, но есть еще один способ добиться их функциональности, а именно классы с несколькими параметрами с функциональными зависимостями. С этими расширениями код может выглядеть так:
{-# 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
Здесь связанный тип переносится на тип параметра класса, а связь между v
и k
, ранее неявная, теперь становится явной с функциональной зависимостью.
Это полностью эквивалентно связанным типам, но IMO обеспечивает гораздо более чистый синтаксис, особенно в функциях, которые используют ваш тип. Для сравнения:
getMap :: (KeyTraits v) => Map (KeyType v) v
и
getMap :: (KeyTraits k v) => Map k v
Это становится более очевидным, когда в объявлении одного типа появляются больше типов и классов типов.
Однако, семейство типов кажется предпочтительным сообществом haskell, и на самом деле все расширение более мощное, чем MPTC + FD, поскольку семейства типов могут быть объявлены без классов типов, а также есть семейства данных.