ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 06.04.2021
Просмотров: 906
Скачиваний: 1
CIRCLE 8. BELIEVING IT DOES AS INTENDED
browser
allows you to look at the objects in the function in which the
browser
call is placed.
recover
allows you to look at those objects as well as the objects
in the caller of that function and all other active functions.
Liberal use of
browser
,
recover
,
cat
and
while you are writing func-
tions allows your expectations and R’s expectations to converge.
A very handy way of doing this is with
trace
. For example, if browsing at
the end of the
myFun
function is convenient, then you can do:
trace(myFun, exit=quote(browser()))
You can customize the tracing with a command like:
trace(myFun, edit=TRUE)
If you run into an error, then debugging is the appropriate action. There are at
least two approaches to debugging. The first approach is to look at the state of
play at the point where the error occurs. Prepare for this by setting the
error
option. The two most likely choices are:
options(error=recover)
or
options(error=dump.frames)
The difference is that with
recover
you are automatically thrown into debug
mode, but with
dump.frames
you start debugging by executing:
debugger()
In either case you are presented with a selection of the frames (environments)
of active functions to inspect.
You can force R to treat warnings as errors with the command:
options(warn=2)
If you want to set the error option in your
.First
function, then you need a
trick since not everything is in place at the time that
.First
is executed:
options(error=expression(recover()))
or
options(error=expression(dump.frames()))
The second idea for debugging is to step through a function as it executes. If
you want to step through function
myfun
, then do:
debug(myfun)
and then execute a statement involving
myfun
. When you are done debugging,
do:
undebug(myfun)
A more sophisticated version of this sort of debugging may be found in the
debug
package.
45
8.1. GHOSTS
CIRCLE 8. BELIEVING IT DOES AS INTENDED
8.1
Ghosts
8.1.1
differences with S+
There are a number of differences between R and S+.
The differences are given in the R FAQ (http://cran.r-project.org/faqs.html).
A few, but not all, are also mentioned here.
8.1.2
package functionality
Suppose you have seen a command that you want to try, such as
fortune(’dog’)
You try it and get the error message:
Error: could not find function "fortune"
You, of course, think that your installation of R is broken. I don’t have evidence
that your installation is not broken, but more likely it is because your current
R session does not include the package where the
fortune
function lives. You
can try:
require(fortune)
Whereupon you get the message:
Error in library(package, ...) :
there is no package called ’fortune’
The problem is that you need to install the package onto your computer. As-
suming you are connected to the internet, you can do this with the command:
install.packages(’fortune’)
After a bit of a preamble, you will get:
Warning message:
package ’fortune’ is not available
Now the problem is that we have the wrong name for the package. Capitalization
as well as spelling is important. The successful incantation is:
install.packages(’fortunes’)
require(fortunes)
fortune(’dog’)
Installing the package only needs to be done once, attaching the package with
the
require
function needs to be done in every R session where you want the
functionality.
The command:
library()
shows you a list of packages that are in your standard location for packages.
46
8.1. GHOSTS
CIRCLE 8. BELIEVING IT DOES AS INTENDED
Figure 8.1: The falsifiers: alchemists by Sandro Botticelli.
8.1.3
precedence
It is a sin to assume that code does what is intended. The following command
clearly intends to produce a sequence from one to one less than
n
:
1:n-1
From the presence of the example here, you should infer that is not what you
get.
Here is another way to make a similar mistake:
10^2:6
If you do:
-2.3 ^ 4.5
you will get a nice, pleasing number. If you do:
x <- -2.3
x ^ 4.5
you will get not-a-number, written as
NaN
. While you may think the two com-
mands are the same, they are not—operator precedence has struck again. If the
latter operation is really what you want, then you need to do:
47
8.1. GHOSTS
CIRCLE 8. BELIEVING IT DOES AS INTENDED
as.complex(x) ^ 4.5
Pay attention to the precedence of operators. If you are at all unsure, then
parentheses can force the command to do what you want.
You can see R’s precedence table by doing:
>
?Syntax
8.1.4
equality of missing values
The following can not possibly work to test for missing values in
x
:
x == NA
Why not?
Here’s a hint:
3 == c(3, 1, 3, NA)
Instead, do:
is.na(x)
8.1.5
testing NULL
Likewise there is
is.null
for testing if an object is
NULL
.
>
xnull <- NULL
>
xnull == NULL
logical(0)
>
xnotnull <- 42
>
xnotnull == NULL
logical(0)
>
is.null(xnull)
[1] TRUE
However, it is often better to test if the length of the object is zero—
NULL
is not
the only zero length object.
>
is.null(numeric(0))
[1] FALSE
48
8.1. GHOSTS
CIRCLE 8. BELIEVING IT DOES AS INTENDED
8.1.6
membership
Another common wish for the
8
==
8
operator is to indicate which elements of
a vector are in some other vector. If you are lucky it will work, but generally
does not. (Actually you will be unlucky if you are writing a function and it does
work—you’ll miss the bug you just put in your function.)
>
x1 <- 10:1
>
x1 == c(4, 6)
[1] FALSE FALSE FALSE FALSE FALSE FALSE
TRUE FALSE
[9] FALSE FALSE
The command above fails to give the locations in
x1
that are equal to 4 and 6.
Use
8
%in%
8
for situations like this:
>
x1 %in% c(4, 6)
[1] FALSE FALSE FALSE FALSE
TRUE FALSE
TRUE FALSE
[9] FALSE FALSE
8.1.7
multiple tests
If you want to do multiple tests, you don’t get to abbreviate. With the
x1
from
just above:
>
x1 == 4 | 6
[1]
TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[10] TRUE
>
x1 == (4 | 6)
[1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
[9] FALSE TRUE
In a second we’ll discuss what is really happening in these two statements. It
would be a good exercise for you to try to figure it out on your own.
But first, the way to actually do the intended operation is:
>
x1 == 4 | x1 == 6
[1] FALSE FALSE FALSE FALSE TRUE FALSE TRUE FALSE
[9] FALSE FALSE
or (better for the more general case):
>
x1 %in% c(4, 6)
[1] FALSE FALSE FALSE FALSE TRUE FALSE TRUE FALSE
[9] FALSE FALSE
Now, what are our bogus attempts doing?
x1 == 4 | 6
49