假设我已经定义了这样的列表:
data List a = Nil | Cons a (List a)
现在我想确保List
仅使用符合特定类型类(例如Ord
)的泛型类型进行实例化。我怎么能这样做?
我知道可以在泛型函数上定义类型类约束,该函数将与List
个实例一起使用,但有没有办法在数据类型本身上定义这样的约束?
答案 0 :(得分:4)
GADT可以在构造函数中捕获约束的字典。
{-# LANGUAGE GADTs #-}
data Sortable a where
Sortable :: Ord a => [a] -> Sortable a
-- ^ ^
-- constructor |
-- |
-- captures an Ord dictionary
在构造函数模式匹配时重新引入字典
sortSortable :: Sortable a -> Sortable a
sortSortable (Sortable xs) = Sortable (sort xs)
-- ^ ^
-- match constructor |
-- |
-- reintroduces `Ord a` dictionary so it can be used in sort
当Sortable a
具有a
实例时,可以构建 Ord a
{-# LANGUAGE StandaloneDeriving #-}
deriving instance Show a => Show (Sortable a)
main = print . sortSortable $ Sortable "Hello, world!"
但不是在它没有
的时候data Z = Z
deriving (Show)
main = print . sortSortable $ Sortable [Z]
这会导致错误,因为Sortable
无法捕获Ord Z
字典,因为一个字典不存在。
No instance for (Ord Z) arising from a use of ‘Sortable’
In the second argument of ‘($)’, namely ‘Sortable [Z]’
In the expression: print . sortSortable $ Sortable [Z]
In an equation for ‘main’:
main = print . sortSortable $ Sortable [Z]