Julia Language
Функции более высокого порядка
Поиск…
Синтаксис
- foreach (f, xs)
- отображение (f, xs)
- фильтр (f, xs)
- уменьшить (f, v0, xs)
- foldl (f, v0, xs)
- foldr (f, v0, xs)
замечания
Функции могут приниматься в качестве параметров и также могут быть получены в качестве типов возврата. Действительно, функции могут быть созданы внутри тела других функций. Эти внутренние функции известны как замыкания .
Функции как аргументы
Функции - объекты в Джулии. Как и любые другие объекты, они могут передаваться как аргументы другим функциям. Функции, которые принимают функции, известны как функции более высокого порядка .
Например, мы можем реализовать эквивалент стандартной функции foreach
стандартной библиотеки, используя функцию f
в качестве первого параметра.
function myforeach(f, xs)
for x in xs
f(x)
end
end
Мы можем проверить, что эта функция действительно работает так, как мы ожидаем:
julia> myforeach(println, ["a", "b", "c"])
a
b
c
Принимая функцию в качестве первого параметра, вместо более позднего параметра мы можем использовать синтаксис блока do Julia. Синтаксис do block - это просто удобный способ передать анонимную функцию в качестве первого аргумента функции.
julia> myforeach([1, 2, 3]) do x
println(x^x)
end
1
4
27
Наша реализация myforeach
выше выше примерно эквивалентна встроенной функции foreach
. Также существуют многие другие встроенные функции более высокого порядка.
Функции более высокого порядка достаточно сильны. Иногда, работая с функциями более высокого порядка, точные выполняемые операции становятся несущественными, и программы могут стать довольно абстрактными. Комбинаторы являются примерами систем высоко абстрактных функций более высокого порядка.
Карта, фильтр и сокращение
Две из наиболее фундаментальных функций более высокого порядка, включенные в стандартную библиотеку, - это map
и filter
. Эти функции являются универсальными и могут работать с любым итерабельным . В частности, они хорошо подходят для вычислений на массивах .
Предположим, у нас есть набор данных о школах. Каждая школа учит конкретному предмету, имеет несколько классов и среднее число учащихся в классе. Мы можем моделировать школу со следующим неизменным типом :
immutable School
subject::Symbol
nclasses::Int
nstudents::Int # average no. of students per class
end
Наш набор учебных пособий будет Vector{School}
:
dataset = [School(:math, 3, 30), School(:math, 5, 20), School(:science, 10, 5)]
Предположим, мы хотим найти количество студентов, общее число которых записано в математической программе. Для этого нам требуется несколько шагов:
- мы должны сузить набор данных только до школ, которые учат математике (
filter
) - мы должны вычислить количество учащихся в каждой школе (
map
) - и мы должны сократить этот список чисел учащихся до одного значения, сумму (
reduce
)
Наивное (не наиболее эффективное) решение просто заключалось бы в том, чтобы напрямую использовать эти три функции более высокого порядка.
function nmath(data)
maths = filter(x -> x.subject === :math, data)
students = map(x -> x.nclasses * x.nstudents, maths)
reduce(+, 0, students)
end
и мы проверяем, что в нашем наборе данных есть 190 математиков:
julia> nmath(dataset)
190
Существуют функции для объединения этих функций и, таким образом, повышения производительности. Например, мы могли бы использовать функцию mapreduce
для выполнения отображения и сокращения за один шаг, что позволило бы сэкономить время и память.
reduce
имеет смысл только для ассоциативных операций, таких как +
, но иногда полезно выполнить сокращение с помощью неассоциативной операции. Функции высокого порядка foldl
и foldr
предоставляются для принудительного выполнения определенного порядка восстановления.