Для определения типа подписи. Вам не нужно знать , что делает функция. Вы можете использовать сигнатуры типов используемых вами функций и делать на них выводы.
Поскольку сигнатура типа вашей функции 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
с ограничениями типов Eq e
и Foldable f
. Таким образом, это означает, что cow
имеет функцию:
cow :: (Eq e, Foldable f) => Bool -> e -> f e -> Bool
cow x y z = x && y `elem` z