Может ли кто-нибудь объяснить типу подписи для первых двух?
Давайте дадим немного более человечно читаемые имена для переменных типа.
function :: (in -> tmp) -> (tmp -> out) -> in -> out
function f1 f2 x = f2 (f1 x)
Этот тип говорит: если вы дадите мне функцию, которая munges входы во временные значения, а функцию, которая munges временных значений в выходные, я дам вам обратно функцию, которая munges входы в выходы. Вы можете представить себе «конвейер обработки данных», где у нас есть множество объектов разных типов, а также операции, которые преобразуют значения одного типа в значения другого типа. Например, вот как я мог бы визуально сделать ваш function
:
in ----- f1 -----> tmp ----- f2 -----> out
\ ^
\ /
`------------- function f1 f2 --------------'
Намеченный интерпретация здесь является то, что вы можете себе представить, взяв два маршрута в этом трубопроводе - либо вы первый операция использование f1
, а затем использовать операцию f2
; или вы можете использовать операцию function f1 f2
, чтобы сделать все это за один раз.
function1 :: (t -> t) -> t -> t
function1 f1 x = f1 (f1 x)
Здесь function1
принимает функцию преобразования t
с (в другие t
с), и возвращает (потенциально другую) функцию преобразования t
с (опять же, в другие t
с). Опять же, опираясь на конвейер обработки данных для этого, вы можете получить что-то вроде этого:
t ----- f1 -----> t ----- f1 -----> t
\ ^
\ /
`------------- function1 f1 --------------'
Почему тип подписи за последние 3 то же самое?
Давайте быстро освежить нашу память об определениях последних трех функций:
function2 f1 f2 x = f1 (f1 x)
function3 f1 f2 x = f1 (f1 (f1 x))
function4 f1 f2 x = f1 (f1 (f1 x))
Хорошо, так что первый интересная вещь о function2
, function3
и function4
является то, что они принимают три аргумента, f1
, f2
и x
, но каждый из них полностью игнорирует f2
- он никогда не упоминается в правой части =
для любого из них. Во-вторых, function3
и function4
определены точно так же, поэтому неудивительно, что им может быть присвоен один и тот же тип.
Принимая эти две вещи во внимание, мы можем сузить вопрос несколько, так что мы спрашиваем, почему эти две функции имеют тип подписи:
function2' f x = f (f x)
function3' f x = f (f (f x))
В частности, их общий тип подписи заключается в следующем:
(t -> t) -> (t -> t)
Как мы уже говорили выше для function1
, это означает, что они принимают на преобразование t
с, и они также случиться, чтобы произвести преобразование на t
с. Еще раз подумав о конвейерах обработки данных, теперь должно быть довольно понятно, почему они имеют один и тот же тип: не имеет значения, применяем ли мы нашу функцию f
два раза или три внутри трубы; тип просто не меняется:
.------------------------ function3' f ------------------------.
/ \
/ v
t ----- f -----> t ----- f -----> t ----- f -----> t
\ ^
\ /
`------------ function2' f -------------'
Предполагая f
это функция, которая начинается в узле с меткой t
и заканчивается в узле с меткой t
, то независимо от того, сколько раз мы применяем f
до остановки, мы всегда возвращается к функции, которая начинается с узла, помеченного t
, и заканчивается на узле с пометкой t
.
Второй аргумент для трех последних функций не должен быть функцией! –
@ Даниэль Вагнер А, я вижу. :) Он не используется в самом определении! – Sibi
Да. sneaky =) –