Мне не ясно, почему функция, определенная как

f g x = g . g x

Имеет тип

f :: (b -> a -> b) -> b -> a -> a -> b

Я бы подумал, что это будет типа

f :: (t -> t) -> t -> t

Может ли кто-нибудь объяснить мне, как разбивается выражение? Благодарность!

6
SuspiciousPineapple 23 Дек 2015 в 11:57

2 ответа

Лучший ответ

Обратите внимание, что приложение-функция имеет наивысший приоритет; операторы приходят позже.

Таким образом, термин g . g x сначала применяется к g к x, а затем составляет результат и сам g. Если x имеет тип b, g должен иметь тип b -> c. Поскольку мы составляем g с g x (последний имеет тип c), c должен быть типом функции, возвращающим b, поэтому c = a -> b. Теперь тип g - b -> a -> b, а тип g . g x - a -> (a -> b); тип f оказывается (b -> a -> b) -> b -> a -> a -> b.

Если вместо этого вам нужно что-то вроде (a -> a) -> a -> a, вы можете попробовать одно из этих

f g x = g (g x)
f g x = (g . g) x
f g x = g . g $ x
f g = g . g
11
lisyarus 23 Дек 2015 в 09:09

Идея заключается в понимании оператора (.), он имеет тип

(.) :: (b -> c) -> (a -> b) -> a -> c

Он берет две функции, каждая с одним параметром, и объединяет их, после применения g x компилятор предполагает, что g на самом деле является g :: a -> b -> c, чтобы удовлетворить сигнатуре (.) :: (b -> c) -> (a -> b) -> a -> c, который принимает две функции с одним аргументом. В противном случае код не будет компилироваться.

И, наконец, если вам нужна подпись f :: (t -> t) -> t -> t, вам понадобится что-то вроде этого:

λ> let applyTwice g = g.g
λ> :t applyTwice
applyTwice :: (a -> a) -> a -> a
λ> applyTwice (*2) 3
12
2
concept3d 23 Дек 2015 в 09:17