为了确定类型签名。您不需要知道函数在做什么。您可以使用您使用的函数的类型签名,并对其进行推断。
由于您的cow 函数的类型签名并不完全正确,我们将展示如何推导出cow 函数的类型签名,然后将其他两个留作练习。
我们看到cow这里有三个参数:x、y和z。目前,我们对x、y和z知之甚少。所以我们将为这些变量分配一个不同的类型变量。所以x :: a、y :: b 和z :: c。
接下来我们可以开始推导类型。 cow的函数定义:
cow x y z = x && y `elem` z
可以写成更规范的格式:
cow x y z = (&&) x (elem y z)
因此我们看到我们在这里使用了两个函数:(&&) :: Bool -> Bool -> Bool 和elem :: (Eq e, Foldable f) => e -> f e -> Bool,我们在这里使用e 而不是f 以避免与我们已经定义的类型变量a 发生“名称冲突” .由于我们使用x 作为(&&) :: Bool -> Bool -> Bool 函数的参数,我们知道x 应该具有Bool 类型,因此a ~ Bool(a 与Bool 的类型相同)。此外,我们因此知道(&&) x :: Bool -> Bool。
接下来我们看到我们调用了elem :: (Eq e, Foldable f) => e -> f e -> Bool。因此,这意味着y,它是应用于elem 的第一个参数,因此具有e 类型,因此是b ~ e。
这进一步意味着elem x因此具有(Eq e, Foldable f) => f e -> Bool类型,我们将此函数应用于z参数。因此这意味着c ~ (Eq e, Foldable f) => f e,并且elem y z 的类型是Bool。
由于elem y z的类型是Bool,这与函数(&&) x匹配,因此(&&) x (elem y z)的类型是Bool。
因此我们得出:
x :: Bool
y :: e
z :: f e
使用 as 类型约束 Eq e 和 Foldable f。因此,这意味着 cow 具有以下功能:
cow :: (Eq e, Foldable f) => Bool -> e -> f e -> Bool
cow x y z = x && y `elem` z