Szukaj…


Składnia

  • foreach (f, xs)
  • mapa (f, xs)
  • filtr (f, xs)
  • zmniejsz (f, v0, xs)
  • foldl (f, v0, xs)
  • foldr (f, v0, xs)

Uwagi

Funkcje mogą być akceptowane jako parametry i mogą być również tworzone jako typy zwracane. Rzeczywiście, funkcje można tworzyć wewnątrz innych funkcji. Te wewnętrzne funkcje są znane jako zamknięcia .

Funkcje jako argumenty

Funkcje są obiektami w Julii. Jak wszystkie inne obiekty, mogą być przekazywane jako argumenty do innych funkcji. Funkcje akceptujące funkcje są znane jako funkcje wyższego rzędu .

Na przykład możemy zaimplementować odpowiednik funkcji foreach biblioteki standardowej, przyjmując funkcję f jako pierwszy parametr.

function myforeach(f, xs)
    for x in xs
        f(x)
    end
end

Możemy przetestować, czy ta funkcja rzeczywiście działa zgodnie z oczekiwaniami:

julia> myforeach(println, ["a", "b", "c"])
a
b
c

Przyjmując funkcję jako pierwszy parametr, zamiast późniejszego parametru, możemy użyć składni Jul blok do. Składnia do block jest po prostu wygodnym sposobem na przekazanie anonimowej funkcji jako pierwszego argumentu funkcji.

julia> myforeach([1, 2, 3]) do x
           println(x^x)
       end
1
4
27

Nasze wdrożenie powyższego myforeach jest mniej więcej równoważne z wbudowaną funkcją foreach . Istnieje również wiele innych wbudowanych funkcji wyższego rzędu.

Funkcje wyższego rzędu są dość potężne. Czasami podczas pracy z funkcjami wyższego rzędu dokładne wykonywane operacje stają się nieistotne, a programy mogą stać się dość abstrakcyjne. Kombinatory są przykładami systemów wysoce abstrakcyjnych funkcji wyższego rzędu.

Mapuj, filtruj i zmniejszaj

Dwie najbardziej podstawowe funkcje wyższego rzędu zawarte w standardowej bibliotece to map i filter . Funkcje te są ogólne i mogą działać na dowolnym iterowalnym . W szczególności są one odpowiednie do obliczeń na tablicach .

Załóżmy, że mamy zbiór danych szkół. Każda szkoła uczy konkretnego przedmiotu, ma kilka klas i średnią liczbę uczniów w klasie. Możemy modelować szkołę następującym niezmiennym typem :

immutable School
    subject::Symbol
    nclasses::Int
    nstudents::Int  # average no. of students per class
end

Nasz zestaw danych szkół będzie Vector{School} :

dataset = [School(:math, 3, 30), School(:math, 5, 20), School(:science, 10, 5)]

Załóżmy, że chcemy znaleźć liczbę studentów zapisanych do programu matematycznego. Aby to zrobić, potrzebujemy kilku kroków:

  • musimy zawęzić zestaw danych do tylko szkół uczących matematyki ( filter )
  • musimy obliczyć liczbę uczniów w każdej szkole ( map )
  • i musimy zredukować listę studentów do jednej wartości, sumy ( reduce )

Naiwnym (mało wydajnym) rozwiązaniem byłoby po prostu bezpośrednie użycie tych trzech funkcji wyższego rzędu.

function nmath(data)
    maths = filter(x -> x.subject === :math, data)
    students = map(x -> x.nclasses * x.nstudents, maths)
    reduce(+, 0, students)
end

i potwierdzamy, że w naszym zestawie danych znajduje się 190 studentów matematyki:

julia> nmath(dataset)
190

Istnieją funkcje, które łączą te funkcje i tym samym poprawiają wydajność. Na przykład moglibyśmy użyć funkcji mapreduce do wykonania mapowania i redukcji w jednym kroku, co oszczędziłoby czas i pamięć.

reduce ma znaczenie tylko dla skojarzonych operacji takich jak + , ale czasami jest to przydatne do przeprowadzenia redukcji za pomocą nie-asocjatywnym pracy. Funkcje wyższego rzędu foldl i foldr są dostarczane w celu wymuszenia określonego rzędu redukcji.



Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow