#haskell #map
#хаскелл #словарь
Вопрос:
Предположим, что кто-то хочет map
перебрать коллекцию, но собирать результаты отображаемой функции только в том случае, если отображаемое значение соответствует определенным критериям. В настоящее время я делаю это как таковое:
func = foldl (acc x, -> (maybeGrab x):acc) []
maybeGrab a
| a > 5 = [someFunc a]
| otherwise = []
Хотя это работает, я уверен, что есть более идиоматический «правильный / распространенный / более узнаваемый» способ сделать это.
Комментарии:
1. Фильтр не делает то, что вам нужно? Или, возможно, mapMaybe из данных. Может быть?
2. @JeffFoster:
mapMaybe
правильный ответ. Вы должны опубликовать это как ответ, чтобы мы могли проголосовать за него.3. Да, Джефф прав. Предстоящий ответ имеет мой голос.
4. Кстати, вы также могли бы использовать concatMap вместо этой фанковой складки (особенно полезно в тех случаях, когда maybeGrab может дать несколько результатов в случае успеха)
Ответ №1:
mapMaybe :: (a -> Maybe b) -> [a] -> [b]
Карта может быть получена из данных.Возможно, пакет выглядит так, как будто он выполняет свою работу. В документации говорится:
Функция mapMaybe — это версия map, которая может выбрасывать элементы. В частности, функциональный аргумент возвращает что-то типа, возможно, b . Если это ничего, ни один элемент не добавляется в список результатов. Если это просто b, то b включается в список результатов.
Ответ №2:
Лично я бы сделал это в два этапа: сначала удалите значения, которые вас не волнуют, затем сопоставьте.
func = map someFunc . filter (>5)
Это также можно красиво выразить как понимание списка.
func xs = [someFunc x | x <- xs, x > 5]
Комментарии:
1. Если желаемый фильтр зависит от полученного значения , вы можете, конечно, изменить порядок :
filter cond . map someFunc
.
Ответ №3:
Хм. Это определенно похоже на место, где фолд просто прекрасен. Как насчет:
func = foldl (acc x -> let a = g x in if a > 5 then a:acc else acc) []
Вот g
функция, которую вы пытаетесь отобразить по списку.
Я не могу придумать ни одной функции, которая изначально объединяет карту и фильтр без сворачивания.
[ПРАВИТЬ / ПРАВИТЬ КОД]
О, по-видимому, есть mapMaybe. Никогда не использовал это раньше. Я исправляюсь. Ха, все время чему-то учишься.
Комментарии:
1. Ик
foldl
! Вы только что потеряли способность передавать этот список.2. Ну , между foldl и foldr нет ничего лучше. Если бы он обрабатывал большой список, не бесконечный, он бы уменьшил накладные расходы на пространство с помощью foldl’. Если, однако, вы упомянули, что он выполнял потоковую передачу или работал с бесконечным списком, foldr был бы единственным способом, которым он мог это сделать.
3. Нет. Накладные расходы на пространство
foldl'
— это Тета (список вывода). Пробел вместоfoldr
O (список вывода).foldl'
выполняет все вычисления перед возвратом,foldr
наследует вычислительную структуру своего пользователя.foldl'
является проигравшим, когда тип вывода не является плоским, как в этом случае.4. Я не уверен, как вы получаете эти большие o / theta. Foldl’ будет суммироваться, например, по списку целых чисел в постоянном пространстве. Foldr создаст больший объем в зависимости от размера списка. Я думаю, что мы оба правы, это просто вопрос того, является ли функция fold ленивой в первом, втором или обоих своих аргументах и уменьшается ли whnf первого аргумента.
5. В любом случае, я думаю, что мы выходим за рамки вопроса OP и должны найти место в другом месте, чтобы продолжить этот разговор.