K31 Imperativeprogrammierung
K31 Imperativeprogrammierung
2 Structured programming
3 Modular programming
4 Debugging
5 Catching errors
The next lectures are all about three programming paradigms and their
realization in R:
Imperative programming,
Object-oriented programming,
Functional programming.
Today, we’re beginning with imperative programming.
Imperative programming
Imperative programming is a programming paradigm that uses statements
that change a program’s state (...). An imperative program consists of
commands for the computer to perform. Imperative programming focuses
on describing how a program operates.a
a
Source: https://en.wikipedia.org/wiki/Imperative_programming Accessed June 6th, 2020.
The program code specifies what needs to be done and in what order
→ Sequence of instructions.
To this end, jump instructions (goto) and nested instructions (if) are
used.
Example: Computing factorials (pseudo code)
1 function(N)
2 i := 1
3 res := 1
4 if (i == N) goto 8
5 i := i + 1
6 res := res * i
7 goto 4
8 return res
Why is this only in pseudo code and not in R code? R doesn’t know explicit
jump instructions! → This original form of imperative programming can’t
be realized in R.
Daniel Horn & Sheila Görz Advanced R Summer Semester 2022 6 / 50
Definition of imperative programming
Imperative programming in R
But, looping statements are part of imperative programming too. Thus, we
can now implement the computation of factorials imperatively in R:
faculty <- function(N) {
res <- 1
for(i in 1:N)
res <- res * i
return(res)
}
So, what’s not imperative programming then? If the source code only
specifies what is to be done, but not how. Example:
Structured programming
Control structures
In imperative programming, control structures control the flow of a
computer program. A control structure is either a branching or a looping
statement.a
a
See: https://en.wikipedia.org/wiki/Control_flow Accessed June 6th, 2020.
The for-loop I
The for-loop II
seq is evaluated at the first call of the loop and can’t be modified by
the function body at a later point. Thus, no infinite loops can occur:
for (i in 1:2) { for (i in x)
print(i) x <- c(x, 0)
i <- i - 1 x
} ## a b
## [1] 1 ## 10 20 0 0
## [1] 2
The for-loop IV
The while-loop I
The while-loop II
The repeat-loop
Vectorization
In R, loops are only seldomly truly necessary. They are needed, for
example, when an iteration depends on previous ones.
Most loops can be rewritten in a functional way → apply.
Even though the apply family is no longer significantly faster than a
loop since R version 3.4.0, it still offers certain advantages, e.g.
concerning parallel computing. More on this in the chapter on
functional programming.
Vectorizing program code makes it faster, nicer and more efficient
than loops and applys. Many R functions already work in a vectorized
way. Thus, before using loops, always ask yourselves if they are truly
necessary.
The if-construct
The if/else-construct I
The if/else-construct II
If an object has no name, then this one is set as the default and
returned when statement matches no other object.
switch("letter", word = "Hallo", number = 1, "Neither")
## [1] "Neither"
Modular programming
Subroutines
Example: Subroutines
x <- seq(-5, 10, length.out = 100)
## [1] 8.560606
Debugging
1. Recognize an error
As trivial as this step might seem, it’s still essential.
Recognizing errors doesn’t simply consist of realizing an error
occurred. It also means to detect results/outputs of your function
thought to be impossible.
2. Make the error reproducible
Create a minimal example that produces the error.
Be mindful of using as few lines of code as possible and to reduce the
runtime of your example to a minimum.
f(10)
[[1]]
[1] "i(c)"
[[2]]
[1] "h(b)"
[[3]]
[1] "g(a)"
[[4]]
[1] "f(10)"
4: i(c) at #1
3: h(b) at #1
2: g(a) at #1
1: f(10)
## trace: sum
## trace: sum
## trace: sum
untrace("sum")
The function debug() works just like browser() - only that the
function is not halted at a specific line but at the first.
Using n, it’s then possible to inspect each line of code.
It’s used like this:
debug("median")
median(1:10)
undebug("median")
Catching errors
fun2(10) fun2("a")
## [1] 2.302585 ## [1] Inf