Ошибка типа Haskell от функционального приложения к функциональной композиции

Этот вопрос связан с этим приложением функции VS Function Composition, на которое ответил antal s-z.

Как это получить?

map has type (a -> b) -> [a] -> [b]
head has type [a] -> a
map head  has type [[a]] -> [a]

Почему следующий код имеет ошибку типа для композиции функции?

 test :: [Char] -> Bool
 test xs = not . null xs

 getMiddleInitials :: [String] -> [Char]
 getMiddleInitials middleNames = map head . filter (\mn -> not . null mn) middleNames

но у этого нет ошибки типа

getFirstElements :: [[a]] -> [a]
getFirstElements = map head . filter (not . null)

Обязательно ли писать функцию без точек, чтобы использовать композицию функций? Я все еще не очень разбираюсь в использовании композиции функций.

Пожалуйста помоги. Спасибо.


person nicholas    schedule 26.06.2010    source источник


Ответы (2)


Ваша ошибка здесь на самом деле очень проста. Если вы помните последнюю часть моего ответа на ваш последний вопрос, оператор . имеет более высокий приоритет, чем что-либо кроме для приложения функции. Итак, рассмотрим ваш пример

test :: [Char] -> Bool
test xs = not . null xs

Анализируется как test xs = not . (null xs). Конечно, null xs имеет тип Bool, и вы не можете составить логическое значение, и поэтому вы получите ошибку типа. Таким образом, вы можете заставить свои примеры работать так:

test :: [Char] -> Bool
test xs = (not . null) xs

getMiddleInitials :: [String] -> [Char]
getMiddleInitials middleNames =
  (map head . filter (\mn -> (not . null) mn)) middleNames

Конечно, писать так необычно, но это нормально.

И нет, помимо безточечного стиля есть и другие способы использования композиции функций. Один из примеров - использовать композицию функций для некоторых вещей (например, аргумент map или filter), но указать остальное. Например, возьмем этот надуманный пример:

rejectMapping :: (a -> Bool) -> (a -> b) -> [a] -> [b]
rejectMapping p f = map f . filter (not . p)

Частично это бессмысленно (например, not . p, и мы остановились на последнем аргументе), но частично (наличие p и f).

person Antal Spector-Zabusky    schedule 26.06.2010
comment
Не совсем понимаю последнюю часть примера rejectMapping. - person nicholas; 27.06.2010
comment
Какую часть этого вы не понимаете? Мотивация, стоящая за этим, что он должен делать или как это работает? Он использует только то, что вы уже видели, так что если вы задумаетесь, то сможете следить за ним! - person Antal Spector-Zabusky; 27.06.2010

Это потому, что приложение-функция x y имеет более высокий приоритет, чем композиция x . y

 test :: [Char] -> Bool
 test xs = (not . null) xs
 -- #      ^          ^

 getMiddleInitials :: [String] -> [Char]
 getMiddleInitials middleNames = (map head . filter (\mn -> (not . null) mn)) middleNames
 -- #                            ^                          ^          ^    ^
person kennytm    schedule 26.06.2010