Ошибка типа Haskell из приложения функции в состав функции - PullRequest
2 голосов
/ 26 июня 2010

Этот вопрос связан с этим Композиция функций VS Приложение функций , на которое ответил 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)

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

Пожалуйста, помогите. Благодарю.

Ответы [ 2 ]

4 голосов
/ 26 июня 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
 -- #                            ^                          ^          ^    ^
3 голосов
/ 26 июня 2010

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

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).

...