我一直在文档和维基上搜索 Haskell 在函数签名中的类型约束。不幸的是,我找不到满意的答案。
此时,我认为自己是初学者,所以如果您看到滥用技术术语或缺乏关于该主题的高级知识,我想请教您的理解。
考虑下面函数签名给出的真实示例:
count :: (Eq e, Num n) => e -> [e] -> n -> n
这个函数有类型约束:
Eq
和Num
,每个都有一个变量,分别是:e
和n
。我也可以提供一个只有一个约束的更简单的签名(例如foo :: Eq a => a -> Bool
)。
但是接下来呢?
考虑假设的例子。我想到他们试图表示属于同一类型约束的多个变量。
-- As far as I tested, the examples below are incorrect
-- and do not reflect proper Haskell syntax
foo :: (Num a b c) => use the variables here
or
foo :: Num a, b, c => use the variables here
我们可以在同一约束中指定多个变量吗,就像我上面尝试的那样?我必须单独指定它们吗?
foo :: Eq a, Eq b ... => use the variables here
有没有一种情况会使用多个相同类型的类型变量,这会带来什么影响?
您还可以定义一个类型族来约束列表中的每个元素:
{-# LANGUAGE DataKinds, TypeFamilies #-}
import Data.Kind (Constraint)
type
AllCls :: (k -> Constraint) -> ([k] -> Constraint)
type family
AllCls cls as where
AllCls cls '[] = ()
AllCls cls (a:as) = (cls a, AllCls cls as)
allEqual :: AllCls Eq [a, b, c] => a -> a -> b -> b -> c -> c -> Bool
allEqual x1 x2 y1 y2 z1 z2 = and
[ x1 == x2
, y1 == y2
, z1 == z2
]
你可以写一个类型同义词,让你可以约束很多类型,而不必每次都重复约束,就像这样:
import Data.Kind (Constraint)
type Three c t1 t2 t3 = (c t1, c t2, c t3) :: Constraint
allEqual :: Three Eq a b c => a -> a -> b -> b -> c -> c -> Bool
allEqual x1 x2 y1 y2 z1 z2 = x1 == x2 && y1 == y2 && z1 == z2