Skip to content

Commit

Permalink
some formatting updates
Browse files Browse the repository at this point in the history
  • Loading branch information
lmiq committed Mar 13, 2023
1 parent c99ef08 commit e570e41
Show file tree
Hide file tree
Showing 7 changed files with 57 additions and 71 deletions.
26 changes: 11 additions & 15 deletions docs/src/anonymous.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Anonymous functions
# Anonymous functions and closures

Anonymous are an important part of the Julia syntax, and permeate many of the codes in Julia.
Anonymous functions and closures are an important part of the Julia syntax.

For example, a simple example of the frequent use of anonymous functions is on calls to the `findfirst` function, which returns the element of an array which first matches a condition:

Expand All @@ -18,30 +18,28 @@ julia> findfirst( x -> sin(x) > 0.5, x )

The `x -> sin(x) > 0.5` is an anonymous function, which one can read as "given `x` return `sin(x) > 0.5`", which in this case can be `true` or `false`.

## Basic syntax
## Basic syntax and closures

Consider the following function:
```julia
a = 5
f(x,a) = a*x
```
An anonymous function which, given `x`, returns the result of `f(x,a)`, is written as
This function is also a "closure", because it "closes over" the variable `a`. Be careful, if written in global scope, this `a` is type-unstable, unless if declared `const`.

We can define an anonymous function which, given `x`, returns the result of `f(x,a)`:
```julia
x -> f(x,a)
```

The anonymous function can be bound to a variable,
The anonymous function can be bound to a label name, as any other value:
```julia
g = x -> f(x,a)
```

and `g` will be a function that, given `x`, returns `f(x,a)`. This definition is similar to

```julia
g(x) = f(x,a)
```

Except that in the latter case the label `g` is bound to the function in definitive:

```julia-repl
Expand All @@ -53,7 +51,6 @@ ERROR: invalid redefinition of constant g
```

While in the former case `g` can be redefined at will, as it is only a label bound to the address of an anonymous function:

```julia-repl
julia> g = x -> f(x,a)
#1 (generic function with 1 method)
Expand All @@ -62,9 +59,8 @@ julia> g = 2
2
```

Anonymous functions for functions with multiple parameters can also be defined, with, for example,

```
Anonymous functions for functions with multiple parameters, and closing over multiple values can be defined likewise:
```julia
(x,y) -> f(x,y,a,b,c)
```

Expand Down Expand Up @@ -98,7 +94,7 @@ julia> function solver(f,x)
solver (generic function with 1 method)
```

Then, for example, let us define a function that depends on three constant parameters besides that the variable `x`:
Then, let us define a function that depends on three constant parameters besides that the variable `x`:
```julia-repl
julia> const a, b, c = 1, 2, 3;
Expand Down Expand Up @@ -146,7 +142,7 @@ the call to the solver in a function that receives the data as parameters, in wh
julia> a, b, c = 1, 2, 3; # not necessarily constant
julia> function h(x,a,b,c)
return solver(x -> a*x^2 + b*x + c,x)
return solver(x -> a*x^2 + b*x + c,x)
end
h (generic function with 1 method)
Expand All @@ -160,7 +156,7 @@ julia> h(x,a,b,c)

# Take away

Passing functions as argument to other functions, in particular if the evaluation of data is required, is practical with the use of anonymous functions. This occurs very frequently in the context of calls to solvers, but very frequently also in the Julia base language, for example in the search and sorting, functions, among many others. One has to keep in mind that the closures are parsed at the calling scope, such that critical code for performance must always be wrapped into functions, to guarantee the constant types of the parameters. Let us just reinforce this point with an example.
Passing functions as argument to other functions, in particular if the evaluation of data is required, is practical with the use of anonymous functions and closures. This occurs very frequently in the context of calls to solvers, but very frequently also in the Julia base language, for example in the search and sorting, functions, among many others. One has to keep in mind that the closures are parsed at the calling scope, such that critical code for performance must always be wrapped into functions, to guarantee the constant types of the parameters. Let us just reinforce this point with an example.

# Example of type-instability

Expand Down
26 changes: 11 additions & 15 deletions docs/src/figures.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,14 @@ Some other options, as `linewidth`, `framestyle`, are a matter of taste. Here I
```julia
using Plots
using LaTeXStrings

plot_font = "Computer Modern"
default(
fontfamily=plot_font,
linewidth=2,
framestyle=:box,
label=nothing,
grid=false
fontfamily=plot_font,
linewidth=2,
framestyle=:box,
label=nothing,
grid=false
)

plot(sort(rand(10)),sort(rand(10)),label="Legend")
plot!(xlabel=L"\textrm{Standard~text}(r) / \mathrm{cm^3}")
plot!(ylabel="Same font as everything")
Expand Down Expand Up @@ -60,16 +58,14 @@ To control the margins, because sometimes depending on the font and figure sizes

```julia
using Plots, Plots.Measures, LaTeXStrings

plot_font = "Computer Modern"
default(
fontfamily=plot_font,
linewidth=2,
framestyle=:box,
label=nothing,
grid=false
fontfamily=plot_font,
linewidth=2,
framestyle=:box,
label=nothing,
grid=false
)

scalefontsizes(1.5)
plot(sort(rand(10)),sort(rand(10)),label="Legend")
plot!(xlabel=L"\textrm{Standard~text}(r) / \mathrm{cm^3}")
Expand All @@ -86,7 +82,7 @@ will produce:
## Save as PDF, convert afterwards

As a reasonable strategy, it is practical to save the plot to a pdf file, with
```
```julia
savefig("./plot.pdf")
```
and convert it later to other formats (`png`, `tiff`, etc), with, for example GIMP. PDF are scalable vector graphics, thus the resolution will be defined only on the conversion step. Additionally, PDF viewers update the file when it is modified, thus one can tune the figure properties by changing the plot generation and viewing the PDF directly, which we will be sure will conform the final figure appearance.
Expand Down
20 changes: 10 additions & 10 deletions docs/src/instability.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,11 @@ Now, we will define a function that uses the value of `x` without passing `x` as

```julia-repl
julia> function f()
s = 0
for val in x
s = s + val
end
return s
s = 0
for val in x
s = s + val
end
return s
end
f (generic function with 1 method)
Expand Down Expand Up @@ -91,11 +91,11 @@ Now, we will define a new function that receives `x` as a parameter, and besides

```julia-repl
julia> function g(x)
s = zero(eltype(x))
for val in x
s = s + val
end
return s
s = zero(eltype(x))
for val in x
s = s + val
end
return s
end
```
Expand Down
6 changes: 3 additions & 3 deletions docs/src/loopscopes.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ My perhaps didactic explanation on the choices made is below. I understand that
```julia
s = 0
for i in 1:3
s = s + i
s = s + i
end
```

Expand All @@ -21,8 +21,8 @@ My perhaps didactic explanation on the choices made is below. I understand that
```julia-repl
julia> s = 0
for i in 1:3
global s
s = s + i
global s
s = s + i
end
```
However, this was inconvenient, because one was not able to copy and paste a code from a function to the REPL. Thus, since Julia 1.5, it was decided that at the REPL the code without the explicit `global s` declaration will work. The `s` variable is still global and the loop will not be efficient, but this in this context it is acceptable because nobody writes critical code directly to the REPL.
Expand Down
39 changes: 18 additions & 21 deletions docs/src/memory.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ is available in `Base` Julia. For example:
```julia
a = @allocated begin
Block to test
end; if a > 0 println(a) end
end; a > 0 && @show a
```
That will print something if the code block allocated something.

Expand All @@ -30,11 +30,11 @@ struct A
x
end
function test(n,x)
@timeit tmr "set y" y = Vector{A}(undef,n)
@timeit tmr "loop" for i in 1:n
@timeit tmr "assign y" y[i] = A(i*x)
end
y
@timeit tmr "set y" y = Vector{A}(undef,n)
@timeit tmr "loop" for i in 1:n
@timeit tmr "assign y" y[i] = A(i*x)
end
y
end
```

Expand Down Expand Up @@ -80,17 +80,16 @@ For example, consider this is the code (file name here: test.jl):

```julia
struct A
x
x
end

function test(n,x)
y = Vector{A}(undef,n)
for i in 1:n
y[i] = A(i*x)
end
y
y = Vector{A}(undef,n)
for i in 1:n
y[i] = A(i*x)
end
y
end

```

Run julia with:
Expand All @@ -111,23 +110,21 @@ julia> test(10,rand()); # gets compiled
julia> Profile.clear_malloc_data() # clear allocations

julia> test(10,rand());

```

Exit Julia, this will generate a file `test.jl.XXX.mem` (extension `.mem`), which, in this case, contains:

```julia
-
- struct A
- x
- x
- end
-
- function test(n,x)
160 y = Vector{A}(undef,n)
0 for i in 1:n
160 y[i] = A(i*x)
- end
0 y
160 y = Vector{A}(undef,n)
0 for i in 1:n
160 y[i] = A(i*x)
- end
0 y
- end

```
Expand Down
8 changes: 4 additions & 4 deletions docs/src/modules.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ Create a file with a function, for example: `f.jl`

```julia
function f(x)
y = 2*x
return y
y = 2*x
return y
end
```

Expand All @@ -27,8 +27,8 @@ Create a file called, for example, `MyModule.jl`, in which you define a module o

```julia
module MyModule
export f
include("./f.jl")
export f
include("./f.jl")
end
```

Expand Down
3 changes: 0 additions & 3 deletions docs/src/nomethod.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ For example, if we define the following function:
```julia-repl
julia> f(x,y) = 2*x + y
f (generic function with 1 method)
```

We have a function that can receive different types of variables (such as scalar integers or floats, or vectors, etc.). This function will be specialized for each type of variables on input. The `@code_typed` macro displays what the codes becomes after the type-specialization of the variables. For example, with integers, we have:
Expand All @@ -20,7 +19,6 @@ CodeInfo(
│ %2 = Base.add_int(%1, y)::Int64
└── return %2
) => Int64
```

Note that the function calls `Base.mul_int` and `Base.add_int`, which are specialized functions to multiply and add integer numbers.
Expand All @@ -35,7 +33,6 @@ CodeInfo(
│ %3 = Base.add_float(%2, y)::Float64
└── return %3
) => Float64
```

Therefore, the code of `f(x,y)` was specialized, at execution time, to different types of variables, and will produce fast compiled versions of the code in each case.
Expand Down

0 comments on commit e570e41

Please sign in to comment.