Почему foldl1 не может применить оператор (==)? - PullRequest
1 голос
/ 06 февраля 2011

С prelude :

foldl1 : он берет первые 2 элемента списка и применяет к ним функцию, затем передает функцию сэтот результат, третий аргумент и т. д.

Почему невозможно написать что-то подобное?

foldl1 (==) [6, 6, 6]
foldl1 (\x y -> x == y) [6, 6, 6]

Ответы [ 4 ]

5 голосов
/ 06 февраля 2011

Если вы хотите проверить, равны ли все элементы списка, быстрое решение будет

allEqual [] = True --(edit: this case is not necessary as pointed out by sepp2k)
allEqual xs = all (== head xs) xs

Кто-нибудь напишет более элегантный способ сделать это, я уверен, но этоисправный.

Редактировать: Спасибо sepp2k за предложения.

2 голосов
/ 06 февраля 2011

РЕДАКТИРОВАТЬ: Антал указывает, что мои рассуждения были неверны. Вот соответствующая часть комментария, которая дает реальную аргументацию (я чувствую себя плохо, принимая этот дословно, но этот ответ был принят, поэтому я не могу удалить его):

Причина, по которой это не работает, состоит в том, что тип foldl1 равен (a -> a -> a) -> [a] -> a, а тип (==) равен Num a => a -> a -> Bool. Поскольку Bool не является Num, тип (==) не соответствует a -> a -> a, и поэтому применение foldl1 отклонено. Если бы это было принято, вы бы столкнулись с ситуацией, когда вы пытались сделать True == 6, но система типов никогда не давала вам такого большого успеха.

Оригинальный ответ (последнее рассуждение неверно):

== займет два Int с и вернет Bool. После первой итерации ваш список примеров становится [True, 6]. Затем он пытается сравнить True с 6, что не удалось.

1 голос
/ 06 февраля 2011

Вот другая версия:

allEqual xs = and $ zipWith (==) xs (tail xs)
0 голосов
/ 06 февраля 2011

Если вы хотите использовать фолд, я бы предложил эту модификацию:

allEqual xs = foldr (\x acc -> x == head xs && acc) True xs

Это очень похоже на уже предложенный all подход. Обратите внимание, что и этот, и all подход могут работать с бесконечными списками (если ответом является False).

Для очень длинных конечных списков, в очень редких случаях вы можете получить лучшую производительность из строгого левого сгиба:

allEqual xs = foldl' (\acc x -> acc && x == head xs) True xs

Но правильное сгибание обычно лучше для этой проблемы, поскольку (в этой реализации) оно выполняет только количество шагов свертывания, равных length $ takeWhile (== head xs) xs. Левый сгиб будет выполнять length xs шагов складывания каждый раз.

...