В этих двух примерах единственные намеки, которые вы имеете на типы функций, проистекают из наблюдения за приложением. В приложении Haskell практически нет синтаксиса, поэтому я буду переписывать их более явно.
two f x = f(f(x))
s x y z = x(z)(y(z))
Теперь мы обнаружим тип этих функций путем постепенного уточнения. Например, начиная с two
мы знаем, что он принимает два аргумента и, следовательно, должен иметь типа, совпадающий с (более общим) типом
two :: a -> b -> c
Мы также знаем, что переменная a
типа выше фактически соответствует функции потому что f
применяется как к x
, так и к f(x)
.
two :: (a -> b) -> c -> d
Поскольку f
применяется к x
мы знаем, что здесь a
и c
должны быть одинаковыми.
two :: (a -> b) -> a -> d
и поскольку мы применяем f
снова к его результату f(x)
мы знаем, что тип результата должен быть таким же, как тип входного
two :: (a -> a) -> a -> b
И, наконец, результатом вызова f
является общим результатом из two
так d
должны также равны a
two :: (a -> a) -> a -> a
Это использует всю информацию, содержащуюся в определении, и является наиболее общим типом, совместимым с определением two
.
Мы можем сделать в основном тот же процесс для s
. Мы знаем, что у него есть 3 аргумента
s :: a -> b -> c -> d
Мы знаем, что первый и второй аргументы являются функциями какого-либо рода.Мы видим, что второй аргумент применяется к одному значению, а первый применяется к двум значениям.
s :: (a -> b -> c) -> (d -> e) -> f -> g
Мы также знаем, что вход первый для обеих функций одинаковы (а именно, это z
каждый раз). Это позволяет нам сделать вывод, что a
, d
и f
тем же самого типа
s :: (a -> b -> c) -> (a -> d) -> a -> e
Мы также знаем, что результат вызова второй функции является вторым аргументом первой функции, так b
и d
должны быть одинаковыми ,
s :: (a -> b -> c) -> (a -> b) -> a -> e
Наконец, результат полностью применения первой функции является конечным результатом s
так c
и e
такие же
s :: (a -> b -> c) -> (a -> b) -> a -> c
Хотя это может быть много, чтобы переварить и добрый размытия, то, что нужно подчеркнуть, состоит в том, что инструменты, которые я использовал для решения этой проблемы, являются примитивными. Эффективно я вводил стрелки (->)
, когда я вижу, что тип был применен к некоторым значениям и, следовательно, должен быть функцией определенного количества аргументов, и я объединяю переменные типа, следуя значениям через их выражение. Это достаточные инструменты для вывода типов простых функций, таких как two
и s
.
Это замечательно, спасибо большое. Я имел доступ к ответу, но требовал пошаговых инструкций, чтобы понять, что происходит на каждом этапе, который вы дали! – AliN