2015-05-04 3 views
4

Учитывая функцию:Применить карту, но только для временного использования

func :: [Int] -> Int 
func x = minimum (map (+5) x) 

И вход: func [1,10].

Я пытаюсь получить выход 1 как 1+5 ниже 1+10, однако, я могу работать только как вывести значение после функции отображения было применено, в то время как я хочу только отображение применить к мое использование minimum, а выход - один из исходных входов.

Как временно использовать карту, пока не найду то, что я хотел, а затем вернул предварительно настроенную версию этого значения?

ответ

4

Существует несколько способов, но лучше всего, вероятно, использовать Data.List.minimumBy. Он выполняет функцию, которая может сравнивать два элемента, а затем находит наименьший элемент, используя эту функцию сравнения. Это очень важно для вашей ситуации. Это тип

> :type minimumBy 
minimumBy :: (a -> a -> Ordering) -> [a] -> a 

Где

> :info Ordering 
data Ordering = LT | EQ | GT -- Defined in 'GHC.Types' 
-- A bunch of instances that don't really matter here 

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

comparer :: Int -> Int -> Ordering 
comparer x y = ... 

Я оставлю реализацию для вас. После этого вы можете использовать его как

func x = minimumBy comparer x 

или просто

func = minimumBy comparer 
2

использование minimumBy (comparing f) (где f будет (+5) для вашего примера)

minimumBy :: (a -> a -> Ordering) -> [a] -> a

comparing :: Ord a => (b -> a) -> b -> b -> Ordering

0

Опцион заключается в использовании пользовательской функции сравнения и minimumBy, как прокомментировали другие. Обратите внимание, что в этом случае ваше преобразование (+5) будет называться дважды для каждого элемента в списке (примерно). Например.

[4,3,2,1] 

приводит к

compare 4 3 => compare (4+5) (3+5) => compare 9 8 => GT 
compare 3 2 => compare (3+5) (2+5) => compare 8 7 => GT 
compare 2 1 => compare (2+5) (1+5) => compare 8 7 => GT 

(3+5),(2+5) Обратите внимание, что вычисляются в два раза выше.

Если операция стоит дорого и просто (+5), может оказаться полезным использовать другой подход. Мы можем предварительно вычислить измененные значения, сохраняя при этом оригинальные из них, если мы строим список пар:

map (\x -> (expensive x, x)) [4,3,2,1] 

выше, функция expensive играет роль (+5) в исходном коде.Затем мы можем взять минимум следующим образом:

snd $ minimumBy (comparing fst) $ map (\x -> (expensive x, x)) [4,3,2,1] 

или даже

snd $ minimum $ map (\x -> (expensive x, x)) [4,3,2,1] 

Последние несколько меньше общего в том, что он требует, чтобы список [4,3,2,1] состоит из несравнимых элементов, в то время как бывший только предполагает что expensive производит нечто сопоставимое.

Однако обратите внимание, что последнее не только вернет случайный элемент в список [4,3,2,1], который минимизирует expensive, но это будет минимальный такой элемент. То есть, когда expensive x == expensive y, функция minimum нарушит связь, сравнивая x и y. Первый не дает такой гарантии.

Смежные вопросы