Невозможно получить безточечном обозначение для компиляции в Haskell

голоса
2

Это работает

unique :: (a -> Bool) -> [a] -> Bool
unique p xs = 1 == length (filter p xs)

Но теперь я хочу его в виде:

unique = (== 1) . length . filter

Сообщение об ошибке:

Couldn't match expected type `[a] -> Bool' with actual type `Bool'
Expected type: b0 -> [a] -> Bool
  Actual type: b0 -> Bool
In the first argument of `(.)', namely `(== 1)'
In the expression: (== 1) . length . filter

Почему это не работает?

Задан 03/09/2014 в 16:07
источник пользователем
На других языках...                            


1 ответов

голоса
6

Это происходит потому , что filterфункция два аргумента. Вы можете обойти эту проблему с помощью удобного оператора

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

-- Important to make it the same precedence as (.)
infixr 9 .:

unique = ((== 1) . length) .: filter

Если вы посмотрите на тип (length .)в GHCi, вы получите

(length .) :: (a -> [b]) -> a -> Int

Это означает , что он принимает единственный аргумент функции , которая возвращает список. Если мы посмотрим на тип filter:

filter :: (a -> Bool) -> [a] -> [a]

Это может быть переписан, чтобы сделать это «единственный аргумент», как

filter :: (a -> Bool) -> ([a] -> [a])

И это вполне очевидно , не совпадает с a -> [b]! В частности, компилятор не может понять, как сделать ([a] -> [a])такой же , как [b], так как одна функция в списках, а другой просто список. Так что это источник ошибки типа.


Интересно, что .:оператор может быть обобщен на работу на функторах вместо:

(.:) :: (Functor f, Functor g) => (a -> b) -> f (g a) -> f (g b)
(.:) = fmap fmap fmap
-- Since the first `fmap` is for the (->) r functor, you can also write this
-- as (.:) = fmap `fmap` fmap === fmap . fmap

Что это хорошо? Скажем , у вас есть Maybe `Int`, и вы хотите , сумма каждого подсписка внутри Just, при условии , что существует:

> let myData = Just [[3, 2, 1], [4], [5, 6]]
> sum .: myData
Just [6, 4, 11]
> length .: myData
Just [3, 1, 2]
> sort .: myData
Just [[1,2,3],[4],[5,6]]

Или что , если вы имели [Maybe Int], и вы хотите , чтобы увеличить каждый:

> let myData = [Just 1, Nothing, Just 3]
> (+1) .: myData
[Just 2,Nothing,Just 4]

Возможности идти дальше и дальше. В основном, это позволяет отобразить функцию в двух вложенных друг в друга функторов, и такого рода структуры выплывает довольно часто. Если вы когда - либо был список внутри Maybeили кортежи внутри списка, или IOвозвращает строку, или что - нибудь подобное, вы столкнетесь с ситуацией , когда вы могли бы использовать (.:) = fmap fmap fmap.

Ответил 03/09/2014 в 16:24
источник пользователем

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more