Использование отфильтрованного списка в новой функции в 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 l
(с sumList
функция).
Цепные функции: (.)
функция
Приведенный выше шаблон довольно распространен: часто мы хотим сначала передать данные через функцию 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
-преобразующие функции.