Использование отфильтрованного списка в новой функции в haskell

Так что я не слишком уверен, как правильно сформулировать это, но скажу, что я хотел получить сумму всех нечетных чисел в списке, есть ли у меня две функции (sumList и getOddNumbers) и объединить их в sumOddList или есть способ положить эти два вместе в одной функции? Если нет лучшей функции, как именно я бы объединил их в sumOddList?

getOddNumbers :: [Integer] -> [Integer]
getOddNumbers [] = []
getOddNumbers (x:xs)
    |odd x = x:getOddNumbers xs
    |otherwise = getOddNumbers xs

sumList :: [Integer] -> Integer
sumList list = case list of
   [] -> 0
   (x:xs) -> x + (sumList xs)

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

Спасибо

(Примечание: я пользуюсь Haskell чуть более 5 недель, и я совершенно нуб)

3 ответа

Решение

Передача вывода в качестве ввода в (другую) функцию

Ну, что вы в основном хотите сделать, это использовать вывод getOddNumbers в качестве входа для sumList функция, поэтому мы можем определить sumOddList функционировать как:

sumOddList :: [Integer] -> Integer
sumOddList l = sumList (getOddNumbers l)

Вот l список, который мы хотим обработать, и результат, таким образом, является приложением функции к результату getOddNumbers lsumList функция).

Цепные функции: (.) функция

Приведенный выше шаблон довольно распространен: часто мы хотим сначала передать данные через функцию g и результат через функцию f, Haskell имеет (.) :: (b -> c) -> (a -> b) -> a -> c функция для "цепочки" функций. Таким образом, мы можем sumList а также getOddNumbers вместе, как:

sumOddList :: [Integer] -> Integer
sumOddList = (.) sumList getOddNumbers

Обратите внимание, что мы больше не используем l параметр здесь. sumOddList здесь определяется как "конвейер", где данные сначала передаются в getOddNumbers и затем "пост-обработан" sumList функция.

(.) Функция также может быть использована как инфиксный оператор:

sumOddList :: [Integer] -> Integer
sumOddList = sumList . getOddNumbers

Ниже приведены три эквивалентных способа написания функции oddSum :: [Integer] -> Integer:

oddSum xs = sumList (getOddNumbers xs)

oddSum xs = sumList $ getOddNumbers xs

oddSum = sumList . getOddNumbers

Кстати, посмотрите на filter а также sum функции в прелюдии, которые вы могли бы заменить getOddNumbers а также sumList соответственно.

или есть способ соединить эти два в одну функцию... sumOddList?

Да, есть.

Цепочка функций с использованием одного выхода в качестве входного другого работает, особенно при ленивой оценке, но оставляет нас зависимыми от слияния, выполняемого компилятором. Что в конце концов не гарантируется (и часто не происходит).

Вместо того, что вы сказали:

mapping f cons x xs = cons (f x) xs

filtering p cons x xs = if (p x) then (cons x xs) else xs

transduce xf cons z xs = foldr (xf cons) z xs

sumOddList xs = transduce (filtering odd) (+) 0 xs

Таким образом,

> sumOddList [1..10]
25
> sum [1,3..10]
25
> transduce (mapping (+1) . filtering odd) (+) 0 [1..10]
35
> sum . filter odd . map (+1) $ [1..10]
35
> sum . map (+1) . filter odd $ [1..10]
30
> transduce (filtering odd . mapping (+1)) (+) 0 [1..10]
30

Это работает, потому что складывает предохранитель, составляя трансформаторы их функций редуктора (например, mapping и filtering выше которого трансформируют свой аргумент редуктор cons):

foldr (+) 0
   . foldr (\x r -> x+1 : r) []
       . foldr (\x r -> if odd x then x : r else r) [] 
         $ [1..10]
=
foldr (+) 0
   . foldr ((\cons x r -> cons (x+1) r) (:)) []
       . foldr ((\cons x r -> if odd x then cons x r else r) (:)) [] 
         $ [1..10]
=
     foldr ((\cons x r -> cons (x+1) r) (+)) 0
       . foldr ((\cons x r -> if odd x then cons x r else r) (:)) [] 
         $ [1..10]
=
         foldr ((\cons x r -> if odd x then cons x r else r) 
                  ((\cons x r -> cons (x+1) r)   (+))) 0 
         $ [1..10]
=
         foldr ( ( (\cons x r -> if odd x then cons x r else r) 
                 . (\cons x r -> cons (x+1) r) ) (+))  0 
         $ [1..10]
=
         foldr ( (filtering odd . mapping (+1))  (+))  0 
         $ [1..10]
=
         foldr (  filtering odd ( mapping (+1)   (+))) 0 
         $ [1..10]
=
         30

Один foldr делать работу из трех. Слияние явно достигается путем составления функций редуктора после cons операция была абстрагирована от них, каждая такая измененная функция становится cons трансформатор, таким образом, может быть составлен с другими такими cons-преобразующие функции.

Другие вопросы по тегам