ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 06.04.2021

Просмотров: 906

Скачиваний: 1

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
background image

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

print

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


background image

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


background image

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


background image

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


background image

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