May 14, 2021 Julia
4. The operator of a special name
7. Variable parameter function
A function in Julia is an object that reflects a set of parameters into an object that returns a value, and Julia's function is not a purely mathematical function, and some functions can change or affect the global state of the program. The basic syntax of defining functions in Julia is:
function f(x,y)
x + y
end
Functions can be refinedly defined in Julia. The above traditional declaration syntax is equivalent to the following compact "assignment form":
f(x,y) = x + y
For assignment forms, the function body is usually a single expression, but it can also be a composite expression (see Compound Expression for details). T his short, simple function definition is common in Julia. Short function syntax is relatively easy to enter and read.
Use parentheses to call functions:
julia> f(2,3)
5
Without parentheses,
f
expression points to a function object that can be passed as a value:
julia> g = f;
julia> g(2,3)
5
There are two ways to call a function: using a special operator syntax with a specific
function name (see the function operator later),
or using
apply
function:
julia> apply(f,2,3)
5
apply
function regards the first argument as a function object and applies it to subsequent arguments.
Like variable names, function names can also use Unicode characters:
julia> ∑(x,y) = x + y
∑ (generic function with 1 method)
The parameters of the Julia function follow the "pass-by-sharing" convention, which is not to pass a value, but rather to pass a reference. F unction parameters themselves are a bit like new variable bindings (the new location of reference values), but they refer to the same value as the value passed. Modifications to variable values, such as arrays, affect other functions.
return
keyword
The value returned by a function is usually the value of the last expression in the function body. I
n the last
f
the
x + y
In C and most command or function languages, the return keyword
return
to return as soon as the value of the expression is evaluated:
function g(x,y)
return x * y
x + y
end
Compare the following two functions:
f(x,y) = x + y
function g(x,y)
return x * y
x + y
end
julia> f(2,3)
5
julia> g(2,3)
6
In pure linear function bodies, such as g, you don't need
return
which does not evaluate
x + y
Y
ou can
x * y
as the last expression of the function and omit
return
R
eturn is useful only if other control
return
are involved.
The following example calculates the length of the beveled edges of the right triangle, where the right-angled edges are x and y, to avoid overflow:
function hypot(x,y)
x = abs(x)
y = abs(y)
if x > y
r = y/x
return x*sqrt(1+r*r)
end
if y == 0
return zero(x)
end
r = x/y
return y*sqrt(1+r*r)
end
The last line of
return
be omitted.
In Julia, most operators are functions that support a specific syntax.
&&
、
||
T
he exception to iso-short-circuit
operations is that they are not functions, because short-circuited values count first the previous value and then the subsequent values.
For function operators, you can enclose the list of arguments in parentheses, just like any other function, as an argument to a function operator:
julia> 1 + 2 + 3
6
julia> +(1,2,3)
6
The infix form is exactly the same as the function form, in fact, the former is internally resolved as the form of a function call.
You can assign, pass, and pass
+
such
*
, and so on, just like any other function:
julia> f = +;
julia> f(1,2,3)
6
However, at this point
f
function does not support the suffix expression.
There are some expressions that call operators with special names:
The expression | Call |
---|---|
[A B C ...]
|
hcat
|
[A, B, C, ...]
|
vcat
|
[A B; C D; ...]
|
hvcat
|
A'
|
ctranspose
|
A.'
|
transpose
|
1:n
|
colon
|
A[i]
|
getindex
|
A[i]=x
|
setindex!
|
These functions exist in
Base.Operators
module.
A function in Julia is a class 1 object that can be assigned to a variable, can be called by a variable after it has been assigned, can be used as an argument and return value, and can even be constructed anonymously:
julia> x -> x^2 + 2x - 1
(anonymous function)
The example above constructs an anonymous function, enters an argument x, and returns the value of the polynthic x^2 plus 2x - 1. T
he main function of an anonymous function is to pass it to a function that accepts other functions as arguments.
The most classic example is
map
function, which applies the function to each value of the array and returns the result array:
julia> map(round, [1.2,3.5,1.7])
3-element Array{Float64,1}:
1.0
4.0
2.0
map
first argument to the map can be a non-anonymous function.
In most cases, however, when such a function does not exist, anonymous functions can simply construct a single-purpose function object without the need for a name:
julia> map(x -> x^2 + 2x - 1, [1,3,-1])
3-element Array{Int64,1}:
2
14
-2
Anonymous functions can
(x,y,z)->2x+y-z
T
he non-parameter anonymous function is
()->3
Non-parameter anonymous functions can be "delayed" calculations, and when this is useful, the code is encapsulated into non-parameter
f()
Julia can simulate returning multiple values by returning multiple groups. H owever, multiple groups do not require parentheses to construct and destruct, thus creating the illusion that multiple values can be returned. The following example returns a pair of child values:
julia> function foo(a,b)
a+b, a*b
end;
If you call this function in an interactive session, but do not assign the return value, you will see that the multiple groups are returned:
julia> foo(2,3)
(5,6)
Julia supports simple multigroup "destructoring" to assign values to variables:
julia> x, y = foo(2,3);
julia> x
5
julia> y
6
You can also return via
return
function foo(a,b)
return a+b, a*b
end
This is the same as the
foo
result.
The list of arguments for a function can sometimes be convenient if it can be any number. T
his function is called a "variable parameter" function and is short for "variable number of parameters".
You can define variable parameter functions by following the
...
after the last argument...
julia> bar(a,b,x...) = (a,b,x)
bar (generic function with 1 method)
Variables
a
b
are the first two common parameters,
x
is a iterative set of parameters trailing with
0
more arguments:
julia> bar(1,2)
(1,2,())
julia> bar(1,2,3)
(1,2,(3,))
julia> bar(1,2,3,4)
(1,2,(3,4))
julia> bar(1,2,3,4,5,6)
(1,2,(3,4,5,6))
In the example above,
x
a multiple group
bar
that are followed to bar.
When a function is called, you can also use ... :
julia> x = (3,4)
(3,4)
julia> bar(1,2,x...)
(1,2,(3,4))
In the example above, the values of a plural group are interpoled exactly as defined by the variable parameter function, or they can be called without fully complying with its function definition:
julia> x = (2,3,4)
(2,3,4)
julia> bar(1,x...)
(1,2,(3,4))
julia> x = (1,2,3,4)
(1,2,3,4)
julia> bar(x...)
(1,2,(3,4))
Objects that are interpoled can also be not multigroups:
julia> x = [3,4]
2-element Array{Int64,1}:
3
4
julia> bar(1,2,x...)
(1,2,(3,4))
julia> x = [1,2,3,4]
4-element Array{Int64,1}:
1
2
3
4
julia> bar(x...)
(1,2,(3,4))
The original function can also be a variable function (in most cases, it should be written as a variable parameter function):
baz(a,b) = a + b
julia> args = [1,2]
2-element Int64 Array:
1
2
julia> baz(args...)
3
julia> args = [1,2,3]
3-element Int64 Array:
1
2
3
julia> baz(args...)
no method baz(Int64,Int64,Int64)
However, if the number of arguments entered is not correct, the function call will fail.
Many times, function parameters have default values. F
or example, the
parseint(num,base)
parses a string to a number of progresses.
base
parameter defaults
10
This scenario can be written as:
function parseint(num, base=10)
###
end
At this point, when a function is called, the argument can be one or two.
When the second argument is not specified,
10
julia> parseint("12",10)
12
julia> parseint("12",3)
5
julia> parseint("12")
12
Optional parameters are convenient for multi-method definitions with different numbers of parameters (see Method for details).
Some functions have a large number of arguments, or have a lot of behavior. I t is difficult to remember how to call such a function. Keyword parameters, allowing parameter names to distinguish between parameters, easy to use and extend these complex interfaces.
For example,
plot
is used to draw a line. T
his function has many options to control the type, width, color, and so on of the line. I
f it receives keyword parameters, we can call forms such as
plot(x, y, width=2)
the line.
Such call methods label parameters for easy reading, or pass some parameters in any order.
Use a function of a keyword argument to define it with a part sign in the function signature:
function plot(x, y; style="solid", width=1, color="black")
###
end
Additional keyword parameters can be matched with ... as in variable
...
functions:
function f(x; y=0, args...)
###
end
Inside the
f
args
a collection of
(key,value)
multiple groups, where
key
the symbol. Y
ou can use a sign to pass the collection when a function is called,
f(x, z=1; args...).
You can also use a dictionary in this case.
The default value of a keyword parameter is evaluated only from left to right when necessary (when the corresponding keyword parameter is not passed), so the default (keyword parameter) expression can call the keyword argument before it.
The difference between optional and keyword parameters is how their default values are valued. W hen an optional argument is valued, only the arguments before it are within scope; I n contrast, when the default value of the keyword parameter is calculated, all parameters are within scope. For example, define a function:
function f(x, a=b, b=1)
###
end
a=b
b
to b outside the scope of
b
not the next
b
However,
a
and b
b
keyword parameters, then they
b
will both be generated in the same scope,
a=b
points to the next argument
b
b
a=b
the expression of the default argument is a
b
assigned).
Passing functions as arguments to other functions is sometimes inconvenient when there are more rows.
The following example calls map in a multi-line
map
map(x->begin
if x < 0 && iseven(x)
return 0
elseif x == 0
return 1
else
return x
end
end,
[A, B, C])
Julia provides a
do
to rewrite this code to make it clearer:
map([A, B, C]) do x
if x < 0 && iseven(x)
return 0
elseif x == 0
return 1
else
return x
end
end
do x
of do x creates an anonymous function with argument
x
and passes it
map
as the first argument.
Similarly,
do a,b
will create an anonymous function with two parameters, and
do
declaration
() -> ....
state that the following is an anonymous function.
How these parameters are initialized depends on the "external" function, where
map
sets
x
A
B
C
in turn, and each will call an anonymous function, as it does in the syntax
map(func, [A, B, C])
Because syntax calls look like normal blocks of code, this syntax makes it easier to use functions to effectively extend the language. T
here are many uses that can be
map
such as management system state.
For example, there is a version of
open
runs code to ensure that the open file ends up closed:
open("outfile", "w") do io
write(io, data)
end
It can be implemented by defining:
function open(f::Function, args...)
io = open(args...)
try
f(io)
finally
close(io)
end
end
In contrast
map
example, the IO here is
open("outfile", "w")
T
he character stream is then passed to
open
the anonymous function that executes the write;
try/finally
is
described in
the control flow.
The use of do block syntax helps you examine documents or implement understanding how parameters of user functions are initialized.