Ключевая идея в получении сигнатур типов:
- Убедитесь, что вы установили приоритеты операторов и функций прямо перед тем, как начать.
Обратите внимание, что приложение-функция имеет наивысший приоритет и ассоциируется слева, поэтому:
- Первый аргумент важнее всего — сначала разберитесь с ним, а затем
- В сигнатурах типов
-> ассоциируется справа.
- Получив тип первого аргумента, замените его везде, где он появляется.
Давайте проработаем ваш пример.
Типы
(.) :: (b -> c) -> (a -> b) -> a -> c
map :: (a -> b) -> [a] -> [b]
uncurry :: (a -> b -> c) -> (a, b) -> c
Дайте каждой функции непересекающиеся имена типов
Во-первых, это сбивает с толку, потому что существует множество a, и все они не означают одно и то же, поэтому я буду каждый раз переименовывать типы новыми буквами.
(.) :: (b -> c) -> (a -> b) -> a -> c
map :: (d -> e) -> [d] -> [e]
uncurry :: (f -> g -> h) -> (f, g) -> h
Включите типы в скобки, связывая их справа
(.) :: (b -> c) -> ((a -> b) -> a -> c)
map :: (d -> e) -> ([d] -> [e])
uncurry :: (f -> (g -> h)) -> ((f, g) -> h)
Сопоставьте тип первого аргумента со всем типом этого аргумента
Теперь давайте посмотрим на выражение (.) map uncurry. Как вы уже поняли, помещение оператора . в квадратные скобки преобразует его в функцию, следующую обычным правилам функций, поэтому (.) map uncurry означает ((.) map) uncurry, а первые типы, подлежащие унификации, относятся к (.) и map.
Теперь (.) имеет первый аргумент (b->c), поэтому (b->c) должен унифицироваться с типом map:
(.) :: ( b -> c ) -> ((a -> b) -> (a -> c))
map :: (d -> e) -> ([d] -> [e])
когда мы подставляем b ~ (d->e) и c ~ ([d]->[e]) в тип (.), мы получаем:
(.) :: ((d->e) -> ([d]->[e])) -> ((a -> (d->e)) -> (a -> ([d]->[e])))
и поэтому map становится первым аргументом этого, поэтому он исчезает из сигнатуры типа, когда мы его указываем, давая
(.) map :: ((a -> (d->e)) -> (a -> ([d]->[e])))
Проверить с помощью интерпретатора, например ghci или Hugs
Hugs> :t (.) map
(map .) :: (a -> b -> c) -> a -> [b] -> [c]
Да, когда мы добавляем скобки из-за правоассоциативности ->, это то же самое.
Перейти к следующему аргументу
Итак, теперь у нас есть
(.) map :: ((a -> (d->e)) -> (a -> ([d]->[e])))
uncurry :: (f -> (g -> h)) -> ((f, g) -> h)
Ужасно заманчиво сопоставить эти два первых аргумента, поскольку они выглядят одинаково, но, конечно, нам нужно сопоставить первый аргумент (.) map с целым типом uncurry:
Сопоставьте тип первого аргумента со всем типом этого аргумента
(.) map :: (( a -> ( d -> e)) -> (a -> ([d]->[e])))
uncurry :: (f->(g->h)) -> ((f,g) -> h)
давая a ~ (f->(g->h)), d ~ (f,g) и e ~ h:
(.) map :: (((f->(g->h)) -> ((f,g)-> h)) -> ((f->(g->h)) -> ([(f,g)]->[h])))
и применение этого к uncurry дает
(.) map uncurry :: ((f->(g->h)) -> ([(f,g)]->[h])))
Проверьте с помощью переводчика
Hugs> :t (.) map uncurry
map . uncurry :: (a -> b -> c) -> [(a,b)] -> [c]
Отлично - мы сделали это!
Работа с операторами
Если мы возьмем пример length . map (.) $ repeat id ++ [] ++ [], нам понадобятся исправления всех этих операторов, но мы можем сначала заключить в скобки приложения функций, потому что они имеют приоритет:
length . map (.) $ repeat id ++ [] ++ []
length . (map (.)) $ (repeat id) ++ [] ++ []
Расположите операторы в порядке приоритета
Найдите исправления операторов, используя команду :i вашего интерпретатора, и расположите их по порядку, начиная с самого высокого:
infixr 9 .
infixr 5 ++
infixr 0 $
Оператор с наивысшим приоритетом . сначала помещается в квадратные скобки:
(length . (map (.))) $ (repeat id) ++ [] ++ []
Затем ++, который ассоциируется справа:
(length . (map (.))) $ ((repeat id) ++ ([] ++ []))
и есть только одно использование $, поэтому я не стал брать его в скобки.
Если хотите, вы можете преобразовать такие операторы, как ++, в функции (++), но я совсем не уверен, что это поможет вам, поэтому я бы оставил это, просто помня, что первый аргумент находится слева.
Обычно помогает начать с самых вложенных скобок.
person
AndrewC
schedule
11.05.2014
(.) map uncurryэто(.)сmapиuncurryв качестве аргументов, а не(.) (map uncurry). - person duplode   schedule 11.05.2014