Suche…


Syntax

  • f (n) = ...
  • Funktion f (n) ... Ende
  • n :: Typ
  • x -> ...
  • f (n) do ... end

Bemerkungen

Neben generischen Funktionen (die am häufigsten vorkommen) gibt es auch integrierte Funktionen. Solche Funktionen umfassen is , isa , typeof , throw und ähnliche Funktionen. Integrierte Funktionen werden normalerweise in C anstelle von Julia implementiert. Sie können daher nicht auf Argumenttypen für den Versand spezialisiert werden.

Platzieren Sie eine Zahl

Dies ist die einfachste Syntax zum Definieren einer Funktion:

square(n) = n * n

Um eine Funktion aufzurufen, verwenden Sie runde Klammern (ohne Leerzeichen dazwischen):

julia> square(10)
100

Funktionen sind Objekte in Julia und wir können sie in der REPL wie alle anderen Objekte zeigen:

julia> square
square (generic function with 1 method)

Alle Julia-Funktionen sind standardmäßig generisch (auch als polymorph bezeichnet ). Unsere square funktioniert genauso gut mit Fließkommazahlen:

julia> square(2.5)
6.25

... oder sogar Matrizen :

julia> square([2 4
               2 1])
2×2 Array{Int64,2}:
 12  12
  6   9

Rekursive Funktionen

Einfache Rekursion

Mit Rekursion und dem ternären bedingten Operator können wir eine alternative Implementierung der eingebauten factorial Funktion erstellen:

myfactorial(n) = n == 0 ? 1 : n * myfactorial(n - 1)

Verwendungszweck:

julia> myfactorial(10)
3628800

Mit Bäumen arbeiten

Rekursive Funktionen sind oft am nützlichsten für Datenstrukturen, insbesondere für Baumdatenstrukturen. Da Ausdrücke in Julia Baumstrukturen sind, kann Rekursion für die Metaprogrammierung sehr nützlich sein. Die folgende Funktion sammelt beispielsweise eine Menge aller Köpfe, die in einem Ausdruck verwendet werden.

heads(ex::Expr) = reduce(∪, Set((ex.head,)), (heads(a) for a in ex.args))
heads(::Any) = Set{Symbol}()

Wir können überprüfen, ob unsere Funktion wie vorgesehen funktioniert:

julia> heads(:(7 + 4x > 1 > A[0]))
Set(Symbol[:comparison,:ref,:call])

Diese Funktion ist kompakt und verwendet eine Vielzahl fortgeschrittener Techniken, z. B. die Funktion zum reduce höherer Ordnung , den Datentyp Set und Generatorausdrücke.

Einführung in den Versand

Wir können die :: -Syntax verwenden, um den Typ eines Arguments abzusetzen.

describe(n::Integer) = "integer $n"
describe(n::AbstractFloat) = "floating point $n"

Verwendungszweck:

julia> describe(10)
"integer 10"

julia> describe(1.0)
"floating point 1.0"

Im Gegensatz zu vielen Sprachen, die normalerweise entweder statische Mehrfachzustellung oder dynamische Einzelzustellung bereitstellen, verfügt Julia über vollständige dynamische Mehrfachzustellung. Das heißt, Funktionen können auf mehrere Argumente spezialisiert sein. Dies ist praktisch, wenn Sie spezielle Methoden für Operationen mit bestimmten Typen und Fallback-Methoden für andere Typen definieren.

describe(n::Integer, m::Integer) = "integers n=$n and m=$m"
describe(n, m::Integer) = "only m=$m is an integer"
describe(n::Integer, m) = "only n=$n is an integer"

Verwendungszweck:

julia> describe(10, 'x')
"only n=10 is an integer"

julia> describe('x', 10)
"only m=10 is an integer"

julia> describe(10, 10)
"integers n=10 and m=10"

Optionale Argumente

Julia erlaubt Funktionen, optionale Argumente zu übernehmen. Hinter den Kulissen wird dies als ein weiterer Sonderfall des Mehrfachversands implementiert. Lösen wir zum Beispiel das beliebte Fizz Buzz-Problem . Standardmäßig machen wir dies für Zahlen im Bereich 1:10 , aber wenn nötig, erlauben wir einen anderen Wert. Wir werden auch verschiedene Sätze für Fizz oder Buzz zulassen.

function fizzbuzz(xs=1:10, fizz="Fizz", buzz="Buzz")
    for i in xs
        if i % 15 == 0
            println(fizz, buzz)
        elseif i % 3 == 0
            println(fizz)
        elseif i % 5 == 0
            println(buzz)
        else
            println(i)
        end
    end
end

Wenn wir fizzbuzz in der REPL untersuchen, heißt es, dass es vier Methoden gibt. Für jede zulässige Kombination von Argumenten wurde eine Methode erstellt.

julia> fizzbuzz
fizzbuzz (generic function with 4 methods)

julia> methods(fizzbuzz)
# 4 methods for generic function "fizzbuzz":
fizzbuzz() at REPL[96]:2
fizzbuzz(xs) at REPL[96]:2
fizzbuzz(xs, fizz) at REPL[96]:2
fizzbuzz(xs, fizz, buzz) at REPL[96]:2

Wir können überprüfen, ob unsere Standardwerte verwendet werden, wenn keine Parameter angegeben werden:

julia> fizzbuzz()
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz

Die optionalen Parameter werden jedoch akzeptiert und respektiert, wenn wir sie angeben:

julia> fizzbuzz(5:8, "fuzz", "bizz")
bizz
fuzz
7
8

Parametrischer Versand

Es ist häufig der Fall, dass eine Funktion auf parametrische Typen wie Vector{T} oder Dict{K,V} , aber die Typparameter sind nicht festgelegt. Dieser Fall kann mit dem parametrischen Versand behandelt werden:

julia> foo{T<:Number}(xs::Vector{T}) = @show xs .+ 1
foo (generic function with 1 method)

julia> foo(xs::Vector) = @show xs
foo (generic function with 2 methods)

julia> foo([1, 2, 3])
xs .+ 1 = [2,3,4]
3-element Array{Int64,1}:
 2
 3
 4

julia> foo([1.0, 2.0, 3.0])
xs .+ 1 = [2.0,3.0,4.0]
3-element Array{Float64,1}:
 2.0
 3.0
 4.0

julia> foo(["x", "y", "z"])
xs = String["x","y","z"]
3-element Array{String,1}:
 "x"
 "y"
 "z"

Man könnte versucht sein, einfach xs::Vector{Number} zu schreiben. Dies funktioniert jedoch nur für Objekte, deren Typ explizit Vector{Number} :

julia> isa(Number[1, 2], Vector{Number})
true

julia> isa(Int[1, 2], Vector{Number})
false

Dies liegt an der parametrischen Invarianz : Das Objekt Int[1, 2] ist kein Vector{Number} , da es nur Int s enthalten kann, wohingegen ein Vector{Number} alle möglichen Zahlen enthalten kann.

Generischen Code schreiben

Dispatch ist eine unglaublich leistungsstarke Funktion, aber häufig ist es besser, generischen Code zu schreiben, der für alle Typen geeignet ist, anstatt den Code für jeden Typ zu spezialisieren. Durch das Schreiben von generischem Code wird die Duplizierung von Code vermieden.

Hier ist zum Beispiel Code, um die Summe der Quadrate eines Vektors von Ganzzahlen zu berechnen:

function sumsq(v::Vector{Int})
    s = 0
    for x in v
        s += x ^ 2
    end
    s
end

Dieser Code funktioniert jedoch nur für einen Vektor von Int s. Es funktioniert nicht bei einem UnitRange :

julia> sumsq(1:10)
ERROR: MethodError: no method matching sumsq(::UnitRange{Int64})
Closest candidates are:
  sumsq(::Array{Int64,1}) at REPL[8]:2

Es funktioniert nicht auf einem Vector{Float64} :

julia> sumsq([1.0, 2.0])
ERROR: MethodError: no method matching sumsq(::Array{Float64,1})
Closest candidates are:
  sumsq(::Array{Int64,1}) at REPL[8]:2

Eine bessere Methode zum Schreiben dieser sumsq Funktion sollte sein

function sumsq(v::AbstractVector)
    s = zero(eltype(v))
    for x in v
        s += x ^ 2
    end
    s
end

Dies funktioniert in den beiden oben aufgeführten Fällen. Aber es gibt einige Sammlungen, in denen wir vielleicht die Quadrate davon zusammenfassen wollen, die in keiner Weise Vektoren sind. Zum Beispiel,

julia> sumsq(take(countfrom(1), 100))
ERROR: MethodError: no method matching sumsq(::Base.Take{Base.Count{Int64}})
Closest candidates are:
  sumsq(::Array{Int64,1}) at REPL[8]:2
  sumsq(::AbstractArray{T,1}) at REPL[11]:2

zeigt, dass wir die Quadrate eines faulen Iterablen nicht summieren können.

Eine noch allgemeinere Implementierung ist einfach

function sumsq(v)
    s = zero(eltype(v))
    for x in v
        s += x ^ 2
    end
    s
end

Was funktioniert in allen Fällen:

julia> sumsq(take(countfrom(1), 100))
338350

Dies ist der idiomatischste Julia-Code und kann mit allen möglichen Situationen umgehen. In einigen anderen Sprachen kann das Entfernen von Typanmerkungen die Leistung beeinträchtigen. Dies ist jedoch in Julia nicht der Fall. Nur die Typenstabilität ist wichtig für die Leistung.

Imperative Fakultät

Für die Definition von mehrzeiligen Funktionen steht eine Langform-Syntax zur Verfügung. Dies kann nützlich sein, wenn wir imperative Strukturen wie Schleifen verwenden. Der Ausdruck in Endposition wird zurückgegeben. Zum Beispiel verwendet die untenstehende Funktion eine for Schleife , um die Fakultät einiger Integer n zu berechnen:

function myfactorial(n)
    fact = one(n)
    for m in 1:n
        fact *= m
    end
    fact
end

Verwendungszweck:

julia> myfactorial(10)
3628800

Bei längeren Funktionen wird häufig die verwendete return Anweisung angezeigt. Die return Anweisung ist in Endposition nicht erforderlich, wird jedoch aus Gründen der Klarheit manchmal verwendet. Eine andere Schreibweise für die obige Funktion wäre beispielsweise

function myfactorial(n)
    fact = one(n)
    for m in 1:n
        fact *= m
    end
    return fact
end

was im Verhalten mit der Funktion oben identisch ist.

Anonyme Funktionen

Pfeilsyntax

Anonyme Funktionen können mit der Syntax -> erstellt werden. Dies ist hilfreich, wenn Sie Funktionen an Funktionen höherer Ordnung übergeben , z. B. die map Funktion. Die folgende Funktion berechnet das Quadrat jeder Zahl in einem Feld A

squareall(A) = map(x -> x ^ 2, A)

Ein Beispiel für die Verwendung dieser Funktion:

julia> squareall(1:10)
10-element Array{Int64,1}:
   1
   4
   9
  16
  25
  36
  49
  64
  81
 100

Mehrzeilige Syntax

Anonyme Funktionen mit mehreren Linien können mithilfe der function erstellt werden. Im folgenden Beispiel werden beispielsweise die Fakultäten der ersten n Zahlen berechnet, wobei jedoch eine anonyme Funktion anstelle der eingebauten factorial .

julia> map(function (n)
               product = one(n)
               for i in 1:n
                   product *= i
               end
               product
           end, 1:10)
10-element Array{Int64,1}:
       1
       2
       6
      24
     120
     720
    5040
   40320
  362880
 3628800

Blockieren Sie die Syntax

Da es so üblich ist, eine anonyme Funktion als erstes Argument an eine Funktion zu übergeben, gibt es eine do Block-Syntax. Die Syntax

map(A) do x
    x ^ 2
end

ist äquivalent zu

map(x -> x ^ 2, A)

Ersteres kann jedoch in vielen Situationen klarer sein, insbesondere wenn in der anonymen Funktion viel berechnet wird. do Blocksyntax ist besonders für die Dateieingabe und -ausgabe aus Gründen der Ressourcenverwaltung hilfreich.



Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow