Пользовательские maximumBy и minimumBy в Haskell


Пройдя через великолепный Хаскелл программирования от первых принципов, я в настоящее время переопределения функции из стандартных библиотек, таких как maximumBy и minimumBy.

Вот мои текущие версии:

myMaximumBy :: (a -> a -> Ordering) -> [a] -> a
-- maximumBy in Data.List also throws an error on empty lists
myMaximumBy _ [] = error "empty list"
myMaximumBy f (x:xs) =
  foldr (\curMax x -> if f x curMax == GT then x else curMax) x xs

myMinimumBy :: (a -> a -> Ordering) -> [a] -> a
myMinimumBy f = myMaximumBy $ flip f

Я знаю, что они не общие функции, но я доберусь до переписывания их с чем-то вроде Maybe позже.

Я рад за любую обратную связь о том, как сделать код короче, более читаемым, и более идиоматические.



Комментарии
2 ответа

Так maximumBy складки список элементов в один элемент, кажется идеальным кандидатом для использования foldr или foldr1. Однако, нам потребуется a -> a -> a вместо a -> a -> Ordering.

Давайте посмотрим на maximum во-первых, который может быть определен через max :: Ord a => a -> a -> a:

maximum :: (Foldable t, Ord a) => t a -> a
maximum = foldr1 max

Это выглядит достаточно простым, чтобы приспособиться к нашей myMaximumBy:

myMaximumBy :: (a -> a -> Ordering) -> [a] -> a
myMaximumBy f = foldr1 (maxBy f)

Мы теперь только нужно maxBy что превращает a -> a -> Ordering в a -> a -> a:

maxBy :: (a -> a -> Ordering) -> a -> a -> a
maxBy comp x y = if x `comp` y == LT then y else x

По сравнению с вашими оригинальное решение, теперь мы


  • заменил явную рекурсию foldr1

  • вводится вспомогательная функция, которая может сделать повторно

Наша новая версия теперь легче поддерживать и использовать.

2
ответ дан 14 февраля 2018 в 06:02 Источник Поделиться

myMaximumBy можно упростить используя foldr1. Аргумент список, тогда можно сделать неявным.

myMaximumBy :: (a -> a -> Ordering) -> [a] -> a
myMaximumBy f = foldr1 (\a b -> if f a b == GT then a else b)

1
ответ дан 13 февраля 2018 в 08:02 Источник Поделиться