Functional Programming in R 4 - Second Edition Thomas Mailund
Functional Programming in R 4 - Second Edition Thomas Mailund Functional Programming in R 4 - Second Edition Thomas Mailund Functional Programming in R 4 - Second Edition Thomas Mailund
Functional Programming in R 4 - Second Edition Thomas Mailund
1.
Download the fullversion and explore a variety of ebooks or textbooks at https://ebookmass.com Functional Programming in R 4 - Second Edition Thomas Mailund _____ Tap the link below to start your download _____ https://ebookmass.com/product/functional-programming- in-r-4-second-edition-thomas-mailund/ Find ebooks or textbooks at ebookmass.com today!
2.
Here are somerecommended products for you. Click the link to download, or explore more at ebookmass.com Functional Programming in R 4: Advanced Statistical Programming for Data Science, Analysis, and Finance Thomas Mailund https://ebookmass.com/product/functional-programming-in-r-4-advanced- statistical-programming-for-data-science-analysis-and-finance-thomas- mailund/ Mastering Functional Programming with Python Brett Neutreon https://ebookmass.com/product/mastering-functional-programming-with- python-brett-neutreon/ Biblical Interpretation in Early Christian Gospels: Volume 4: The Gospel of John Thomas R. Hatina https://ebookmass.com/product/biblical-interpretation-in-early- christian-gospels-volume-4-the-gospel-of-john-thomas-r-hatina/ Introducing ReScript: Functional Programming for Web Applications 1st Edition Danny Yang https://ebookmass.com/product/introducing-rescript-functional- programming-for-web-applications-1st-edition-danny-yang/
3.
Advanced R 4Data Programming and the Cloud: Using PostgreSQL, AWS, and Shiny 2nd Edition Matt Wiley https://ebookmass.com/product/advanced-r-4-data-programming-and-the- cloud-using-postgresql-aws-and-shiny-2nd-edition-matt-wiley/ Linux Kernel Programming - Second Edition Kaiwan N. Billimoria https://ebookmass.com/product/linux-kernel-programming-second-edition- kaiwan-n-billimoria/ Asynchronous Programming with SwiftUI and Combine: Functional Programming to Build UIs on Apple Platforms 1st Edition Peter Friese https://ebookmass.com/product/asynchronous-programming-with-swiftui- and-combine-functional-programming-to-build-uis-on-apple- platforms-1st-edition-peter-friese/ Learn Aspen Plus in 24 Hours, Second Edition Thomas A. Adams https://ebookmass.com/product/learn-aspen-plus-in-24-hours-second- edition-thomas-a-adams/ The Art of Multiprocessor Programming. Second Edition Maurice Herlihy https://ebookmass.com/product/the-art-of-multiprocessor-programming- second-edition-maurice-herlihy/
Any source codeor other supplementary material referenced by the author in this book is available to readers on GitHub (https://github.com/Apress). For more detailed information, please visit http://www.apress.com/source-code.
9.
Acknowledgments I would liketo thank Duncan Murdoch and the people on the R-help mailing list for helping me work out a kink in lazy evaluation in the trampoline example.
10.
Table of Contents Chapter1:Introduction Chapter 2:Functions in R Writing Functions in R Named Parameters and Default Parameters The “Gobble Up Everything Else” Parameter:“. . . ” Lazy Evaluation Functions Don’t Have Names Vectorized Functions Infix Operators Replacement Functions Chapter 3:Pure Functional Programming Writing Pure Functions Recursion As Loops The Structure of a Recursive Function Tail-Recursion Runtime Considerations Chapter 4:Scope and Closures Environments and Functions Environment Chains, Scope, and Function Calls Scopes, Lazy Evaluation, and Default Parameters Nested Functions and Scopes Closures Reaching Outside Your Innermost Scope Lexical and Dynamic Scope Chapter 5:Higher-Order Functions
11.
Currying A Parameter BindingFunction Continuation-Passing Style Thunks and Trampolines Chapter 6:Filter, Map, and Reduce The General Sequence Object in R Is a List Filtering Sequences Mapping over Sequences Reducing Sequences Bringing the Functions Together The Apply Family of Functions sapply, vapply, and lapply The apply Function The tapply Function Functional Programming in purrr Filter-like Functions Map-like Functions Reduce-like Functions Chapter 7:Point-Free Programming Function Composition Pipelines Chapter 8:Conclusions Index
12.
About the Author ThomasMailund is Senior Software Architect at Kvantify, a quantum computing company from Denmark. He has a background in math and computer science. He now works on developing algorithms for computational problems applicable for quantum computing. He previously worked at the Bioinformatics Research Centre, Aarhus University, on genetics and evolutionary studies, particularly comparative genomics, speciation, and gene flow between emerging species. He has published Beginning Data Science in R with Apress, as well as other books out there.
13.
About the TechnicalReviewer Megan J. Hirni is currently pursuing her PhD at the University of Missouri-Columbia with a focus on applied statistics research. In addition to her love for R coding, Megan loves meeting new people and learning new topics in multifaceted fields.
just as withother data, you can write transformations that take functions as input and produce (other) functions as output. You can thus write simple functions, then adapt them (using other functions to modify them), and combine them in various ways to construct complete programs. The R programming language supports procedural programming, object-oriented programming, and functional programming, but it is mainly a functional language. It is not a “pure” functional language. Pure functional languages will not allow you to modify the state of the program by changing values parameters hold and will not allow functions to have side effects (and need various tricks to deal with program input and output because of it). R is somewhat close to “pure” functional languages. In general, data is immutable, so changes to data inside a function do ordinarily not alter the state of data outside that function. But R does allow side effects, such as printing data or making plots, and, of course, allows variables to change values. Pure functions have no side effects, so a function called with the same input will always return the same output. Pure functions are easier to debug and to reason about because of this. They can be reasoned about in isolation and will not depend on the context in which they are called. The R language does not guarantee that the functions you write are pure, but you can write most of your programs using only pure functions. By keeping your code mostly purely functional, you will write more robust code and code that is easier to modify when the need arises. You will want to move the impure functions to a small subset of your program. These functions are typically those that need to sample random data or that produce output (either text or plots). If you know where your impure functions are, you know when to be extra careful with modifying code. The next chapter contains a short introduction to functions in R. Some parts you might already know, and so feel free to skip ahead, but I give a detailed description of how functions are defined and used to ensure that we are all on the same page. The following chapters then move on to more complex issues.
square(1:5) ## [1] 14 9 16 25 The shorter syntax, (x) x**2, is intended for so-called “lambda expressions,” and the backslash notation is supposed to look like the Greek letter lambda, λ. Lambda expressions are useful when we need to provide short functions as arguments to other functions, which is something we return to in later chapters. Usually, we use the function() syntax when defining reusable functions, and I will stick to this notation in every case where we define and name a function the way we did for square earlier. The function we have written takes one argument, x, and returns the result x**2. The return value of a function is always the last expression evaluated in it. If you write a function with a single expression, you can write it as earlier, but for more complex functions, you will typically need several statements in it. If you do, you can put the function’s body in curly brackets like this: square <- function(x) { x**2 } The following function needs the curly brackets since it needs three separate statements to compute its return value, one for computing the mean of its input, one for getting the standard deviation, and a final expression that returns the input scaled to be centered on the mean and having one standard deviation. rescale <- function(x) { m <- mean(x) s <- sd(x) (x - m) / s } The first two statements are just there to define some variables we can use in the final expression. This is typical for writing short functions.
18.
Variables you assignto inside a function will only be visible from inside the function. When the function completes its execution, the variables cease to exist. From inside a function, you can see the so- called local variables—the function arguments and the variables you assign to in the function body—and you can see the so-called global variables—those assigned to outside of the function. Outside of the function, however, you can only see the global variables. At least that is a good way to think about which variables you can see at any point in a program until we get to the gritty details in Chapter 4. For now, think in terms of global variables and local variables, where anything you write outside a function is in the first category and can be seen by anyone, and where function parameters and variables assigned to inside functions are in the second category; see Figure 2-1. If you have the same name for both a global and a local variable, as in the figure where we have a global variable x and a function parameter x, then the name always refers to the local variable. Figure 2-1 Local and global variables Assignments are really also expressions. They return an object, the value that is being assigned; they just do so quietly. R considers some expressions “invisible,” and while they do evaluate to some value or other—all expressions do—R does not print the result. Assignments are invisible in this way; they do return to the value on the right-hand side of the assignment, but R makes the result invisible. You can remove this invisibility by putting an assignment in parentheses. The
19.
parentheses make Rremove the invisibility of the expression result, so you see the actual value: (x <- 1:5) ## [1] 1 2 3 4 5 You can also go the other way and make a value invisible. When you evaluate an expression, R will print it: x**2 ## [1] 1 4 9 16 25 but if you put the expression in a call to invisible, R will not print the result: invisible(x**2) We usually use assignments for their side effect, assigning a name to a value, so you might not think of them as expressions, but everything you do in R is actually an expression. That includes control structures like if-statements and for-loops. They return values. They are actually functions themselves, and they return values. If you evaluate an if-statement, you get the value of the last expression in the branch it takes: if (2 + 2 == 4) "Brave New World" else "1984" ## [1] "Brave New World" If you evaluate a loop, you get the value NULL (and not the last expression in its body): x <- for (i in 1:10) i x ## NULL
20.
Even parentheses andsubscripting are functions. Parentheses evaluate to the value you put inside them (but stripped of invisibility), and subscripting, [...] or [[...]], evaluates to some appropriate value on the data structure you are accessing (and you can define how this will work for your own data structures if you want to). If you want to return a value from a function before its last expression, you can use the return function. It might look like a keyword, but it is a function, and you need to include the parentheses when you use it. Many languages will let you return a value by writing return expression Not R. In R, you need to write return(expression) If you are trying to return a value, this will not cause you much trouble. R will tell you that you have a syntax error if you use the former and not the latter syntax. Where it can be a problem is if you want to return from a function without providing a value (in which case the function automatically returns NULL). If you write something like this: f <- function(x) { if (x < 0) return; # Something else happens here... } you will not return if x is negative. The if-expression evaluates to the function return, which is not what you want. Instead, you must write f <- function(x) { if (x < 0) return(); # Something else happens here... }
21.
If x isnegative, we call return(), which will return NULL. (To return a value, val, use return(val)). Return is usually used to exit a function early and isn’t used that much in most R code. It is easier to return a value by just making it the last expression in a function than it is to explicitly use return. But you can use it to return early like this: rescale <- function(x, only_translate) { m <- mean(x) translated <- x - m if (only_translate) return(translated) s <- sd(x) translated / s } rescale(1:4, TRUE) ## [1] -1.5 -0.5 0.5 1.5 rescale(1:4, FALSE) ## [1] -1.1618950 -0.3872983 0.3872983 1.1618950 This function has two arguments, x and only_translate. Your functions can have any number of parameters. When a function takes many arguments, however, it becomes harder to remember in which order you have to put them. To get around that problem, R allows you to provide the arguments to a function using their names. So the two function calls earlier can also be written as rescale(x = 1:4, only_translate = TRUE) rescale(x = 1:4, only_translate = FALSE) Named Parameters and Default Parameters If you use named arguments, the order doesn’t matter, so this is also equivalent to these function calls: rescale(only_translate = TRUE, x = 1:4)
22.
rescale(only_translate = FALSE,x = 1:4) You can mix positional and named arguments. The positional arguments have to come in the same order as used in the function definition, and the named arguments can come in any order. All the following four function calls are equivalent: rescale(1:4, only_translate = TRUE) rescale(only_translate = TRUE, 1:4) rescale(x = 1:4, TRUE) rescale(TRUE, x = 1:4) When you provide a named argument to a function, you don’t need to use the full parameter name. Any unique prefix will do. So we could also have used the following two function calls: rescale(1:4, o = TRUE) rescale(o = TRUE, 1:4) This is convenient for interactive work with R because it saves some typing, but I do not recommend it when you are writing programs. It can easily get confusing, and if the author of the function adds a new argument to the function with the same prefix as the one you use, it will break your code. If the function author provides a default value for that parameter, your code will not break if you use the full argument name. Not breaking, in a situation like this, is a whole lot worse than breaking, because the code will not do the right thing and you will not be immediately aware of that. Now, default parameters are provided when the function is defined. We could have given rescale a default parameter for only_translate like this: rescale <- function(x, only_translate = FALSE) { m <- mean(x) translated <- x - m if (only_translate) return(translated) s <- sd(x) translated / s }
23.
Then, if wecall the function, we only need to provide x if we are happy with the default value for only_translate. rescale(1:4) ## [1] -1.1618950 -0.3872983 0.3872983 1.1618950 R makes heavy use of default parameters. Many commonly used functions, such as plotting functions and model fitting functions, have lots of arguments. These arguments let you control in great detail what the functions do, making them very flexible, and because they have default values, you usually only have to worry about a few of them. The “Gobble Up Everything Else” Parameter: “...” There is a special parameter all functions can take called .... This parameter is typically used to pass parameters on to functions called within a function. To give an example, we can use it to deal with missing values, NA, in the rescale function. We can write (where I’m building from the shorter version) rescale <- function(x, ...) { m <- mean(x, ...) s <- sd(x, ...) (x - m) / s } If we give this function a vector x that contains missing values, it will return NA: x <- c(NA, 1:3) rescale(x) ## [1] NA NA NA NA It would also have done that before because that is how the functions mean and sd work. But both of these functions take an
24.
additional parameter, na.rm,that will make them remove all NA values before they do their computations. Our rescale function can do the same now: rescale(x, na.rm = TRUE) ## [1] NA -1 0 1 The first value in the output is still NA. Rescaling an NA value can’t be anything else. But the rest are rescaled values where that NA was ignored when computing the mean and standard deviation. The “...” parameter allows a function to take any named parameter at all. If you write a function without it, it will only take the predetermined parameters, but if you add this parameter, it will accept any named parameter at all: f <- function(x) x g <- function(x, ...) x f(1:4, foo = "bar") ## Error in f(1:4, foo = "bar"): unused argument (foo = "bar") g(1:4, foo = "bar") ## [1] 1 2 3 4 If you then call another function with “...” as a parameter, then all the parameters the first function doesn’t know about will be passed on to the second function: f <- function(...) list(...) g <- function(x, y, ...) f(...) g(x = 1, y = 2, z = 3, w = 4) ## $z ## [1] 3 ## ## $w
25.
## [1] 4 Inthe preceding example, function f creates a list of named elements from “...”, and as you can see, it gets the parameters that g doesn’t explicitly take. Using “...” is not particularly safe. It is often very hard to figure out what it actually does in a particular piece of code. What is passed on to other functions depends on what the first function explicitly takes as arguments, and when you call a second function using it, you pass along all the parameters in it. If the function you call doesn’t know how to deal with them, you get an error: f <- function(w) w g <- function(x, y, ...) f(...) g(x = 1, y = 2, z = 3, w = 4) ## Error in f(...): unused argument (z = 3) In the rescale function, it would have been much better to add the rm.na parameter explicitly. That being said, “...” is frequently used in R. Particularly because many functions take very many parameters with default values, and adding these parameters to all functions calling them would be tedious and error-prone. It is also the best way to add parameters when specializing generic functions, which is a topic for another book, Advanced Object-Oriented Programming in R, by yours truly. Lazy Evaluation Expressions used in a function call are not evaluated before they are passed to the function. Most common languages have so-called pass-by- value semantics, which means that all expressions given to parameters of a function are evaluated before the function is called. In R, the semantic is “call-by-promise,” also known as “lazy evaluation.” When you call a function and give it expressions as its arguments, these are not evaluated at that point. What the function gets is not the result of evaluating them but the actual expressions, called “promises” (they are promises of an evaluation to a value you can get when you
26.
need it), thusthe term “call-by-promise.” These expressions are only evaluated when they are actually needed, thus the term “lazy evaluation.” This has several consequences for how functions work. First of all, an expression that isn’t used in a function isn’t evaluated: f <- function(a, b) a f(2, stop("error if evaluated")) ## [1] 2 f(stop("error if evaluated"), 2) ## Error in f(stop("error if evaluated"), 2): error if evaluated If you have a parameter that can only be meaningfully evaluated in certain contexts, it is safe enough to have it as a parameter as long as you only refer to it when those necessary conditions are met. It is also very useful for default values of parameters. These are evaluated inside the scope of the function, so you can write default values that depend on other parameters: f <- function(a, b = a) a + b f(a = 2) ## [1] 4 This does not mean that all the expressions are evaluated inside the scope of the function, though. We discuss scopes in Chapter 4, but for now, you can think of two scopes: the global scope where global variables live and the function scope that has parameters and local variables as well. If you call a function like this: f(a = 2, b = a)
27.
you will getan error if you expect b to be the same as a inside the function. If you are lucky and there isn’t any global variable called a, you will get a runtime error. If you are unlucky and there is a global variable called a, that is what b will be assigned, and if you expect it to be set to 2 here, your code will just give you an incorrect answer. However, it is safe for a default parameter to be an expression that uses some of the other function arguments. The default parameters are evaluated after the function is called, where they have access to the other arguments. An expression you use when calling a function, however, doesn’t see the local variables inside the function, but the variables you have in the calling scope. Figure 2-2 Where arguments and default arguments are evaluated Consider Figure 2-2. We have a function, f, that takes two arguments, a and b, where b has a default of 2*a. If we call it as f(2*a, b = 2*a), then both arguments will be expressions that R knows have to be evaluated in the global scope where a is the list 1 2 3 4 5 and where we don’t have a b. Neither parameter will be evaluated until we look at the arguments, but when we do, both will be evaluated and to the same value since both are 2*a and a refers to the global a. If, however, we call f as f(2*a) so b gets the default value, we are in a different situation. Inside the function call, a still refers to the expression 2*a to be evaluated in the global scope, but b, also still referring to the expression 2*a, will be evaluated in the local scope. So, if we evaluate b, we will first evaluate the parameter a to get 2*a
28.
(evaluated using theglobal a) 2 4 6 8 10, and then we evaluate 2*a with this local a to get 4 8 12 16 20. So, while arguments aren’t evaluated yet when you call a function, they will be when you access them. If they are default arguments, you evaluate them inside the function, and if they were provided in the function call, you evaluated them outside the call, where the function was called. This also means that you cannot change what an expression evaluates to just by changing a local variable: a <- 4 f <- function(x) { a <- 2 x } f(1 + a) ## [1] 5 In this example, the expression 1 + a is evaluated inside f, but the a in the expression is the a outside of f and not the a local variable inside f. This is of course what you want. If expressions really were evaluated inside the scope of the function, then you would have no idea what they evaluated to if you called a function with an expression. It would depend on any local variables the function might use. Because expressions are evaluated in the calling scope and not the scope of the function, you mostly won’t notice the difference between call-by-value and call-by-promise. There are certain cases where the difference can bite you, though, if you are not careful. As an example, we can consider this function: f <- function(a) function(b) a + b This might look a bit odd if you are not used to it, but it is a function that returns another function. We will see many examples of this kind of functions in later chapters.
29.
When we callf with a parameter a, we get a function back that will add a to its argument: f(2)(2) ## [1] 4 We can create a list of functions from this f: ff <- vector("list", 4) for (i in 1:4) { ff[[i]] <- f(i) } ff ## [[1]] ## function(b) a + b ## <bytecode: 0x7fe446ad68a8> ## <environment: 0x7fe446a07ca0> ## ## [[2]] ## function(b) a + b ## <bytecode: 0x7fe446ad68a8> ## <environment: 0x7fe446ad71e8> ## ## [[3]] ## function(b) a + b ## <bytecode: 0x7fe446ad68a8> ## <environment: 0x7fe446ad7098> ## ## [[4]] ## function(b) a + b ## <bytecode: 0x7fe446ad68a8> ## <environment: 0x7fe446ad6f48> Here, ff contains four functions, and the idea is that the first of these adds 1 to its argument, the second adds 2, and so on.
30.
If we callthe functions in ff, however, weird stuff happens: ff[[1]](1) ## [1] 5 When we get the element ff[[1]], we get the first function we created in the loop. If we substitute into f the value we gave in the call, this is function(b) i + b The parameter a from f has been set to the parameter we gave it, i, but i has not been evaluated at this point! When we call the function, the expression is evaluated, in the global scope, but there i now has the value 4 because that is the last value it was assigned in the loop. The value of i was 1 when we called it to create the function, but it is 5 when the expression is actually evaluated. This also means that we can change the value of i before we evaluate one of the functions, and this changes it from the value we intended when we created the function: i <- 1 ff[[2]](1) ## [1] 2 This laziness is only in effect the first time we call the function. If we change i again and call the function, we get the same value as the first time the function was evaluated: i <- 2 ff[[2]](1) ## [1] 2 We can see this in effect by looping over the functions and evaluating them:
31.
results <- vector("numeric",4) for (i in 1:4) { results[i] <- ff[[i]](1) } results ## [1] 5 2 4 5 We have already evaluated the first two functions, so they are stuck at the values they got at the time of the first evaluation. The other two get the intended functionality but only because we are setting the variable i in the loop where we evaluate the functions. If we had used a different loop variable, we wouldn’t have been so lucky. This problem is caused by having a function with an unevaluated expression that depends on variables in the outer scope. Functions that return functions are not uncommon, though, if you want to exploit the benefits of having a functional language. It is also a consequence of allowing variables to change values, something most functional programming languages do not allow for such reasons. You cannot entirely avoid it, though, by avoiding for-loops. If you call functions that loop for you, you do not necessarily have control over how they do that, and you can end up in the same situation. The way to avoid the problem is to force an evaluation of the parameter. If you evaluate it once, it will remember the value, and the problem is gone. You can do that by just writing the parameter as a single statement. That will evaluate it. It is better to use the function force though, to make it explicit that this is what you are doing. It really just gives you the expression back, so it works exactly as if you just wrote the parameter, but the code makes clear why you are doing it. If you do this, the problem is gone: f <- function(a) { force(a) function(b) a + b } ff <- vector("list", 4)
32.
for (i in1:4) { ff[[i]] <- f(i) } ff[[1]](1) ## [1] 2 i <- 1 ff[[2]](1) ## [1] 3 Functions Don’t Have Names The last thing I want to stress when we talk about defining functions is that functions do not have names. Variables have names, and variables can refer to functions, but these are two separate things. In many languages, such as Java, Python, or C++, you define a function, and at the same time, you give it an argument. When possible at all, you need a special syntax to define a function without a name. Not so in R. In R, functions do not have names, and when you define them, you are not giving them a name. We have given names to all the functions we have used earlier by assigning them to variables right where we defined them. We didn’t have to. It is the “function(...) ...” syntax that defines a function. We are defining a function whether we assign it to a variable or not. We can define a function and call it immediately like this: (function(x) x**2)(2) ## [1] 4 We would never do this, of course. Anywhere we would want to define an anonymous function and immediately call it, we could instead just put the body of the function. Functions we want to reuse we have to give a name so we can get to them again.
33.
The syntax fordefining functions, however, doesn’t force us to give them names. When you start to write higher-order functions, that is, functions that take other functions as input or return functions, this is convenient. Such higher-order functions are an important part of functional programming, and we will see much of them later in the book. Vectorized Functions Expressions in R are vectorized. When you write an expression, it is implicitly working on vectors of values, not single values. Even simple expressions that only involve numbers really are vector operations. They are just vectors of length 1. For longer vectors, expressions work component-wise. So if you have vectors x and y, you can subtract the first from the second component-wise just by writing x - y: x <- 1:5 y <- 6:10 x – y ## [1] -5 -5 -5 -5 -5 If the vectors are not of the same length, the shorter vector is just repeated as many times as is necessary. This is why you can, for example, multiply a number to a vector: 2 * x ## [1] 2 4 6 8 10 Here, 2 is a vector of length 1 and x a vector of length 5, and 2 is just repeated five times. You will get a warning if the length of the longer vector is not divisible by the length of the shorter vector, and you generally want to avoid this. The semantic is the same, though: R just keeps repeating the shorter vector as many times as needed. x <- 1:6
34.
y <- 1:3 x– y ## [1] 0 0 0 3 3 3 Depending on how a function is written, it can also be used in vectorized expressions. R is happy to use the result of a function call in a vector expression as long as this result is a vector. This is not quite the same as the function operating component-wise on vectors. Such functions we can call vectorized functions. Most mathematical functions such as sqrt, log, cos, and sin are vectorized, and you can use them in expressions: log(1:3) - sqrt(1:3) ## [1] -1.0000000 -0.7210664 -0.6334385 Functions you write yourself will also be vectorized if their body consists only of vectorized expressions: f <- function(a, b) log(a) - sqrt(b) f(1:3, 1:3) ## [1] -1.0000000 -0.7210664 -0.6334385 The very first function we wrote in this book, square, was also a vectorized function. The function scale was also, although the functions it used, mean and sd, are not; they take vector input but return a summary of the entire vector and do not operate on the vector component-wise. A function that uses control structures usually will not be vectorized. We can write a comparison function that returns -1 if the first argument is smaller than the second and 1 if the second is larger than the first, and zero otherwise like this: compare <- function(x, y) { if (x < y) { -1 } else if (y < x) {
35.
1 } else { 0 } } Thisfunction will work fine on single values but not on vectors. The problem is that the if-expression only looks at the first element in the logical vector x < y. (Yes, x < y is a vector because < is a vectorized function.) To handle if-expressions, we can get around this problem by using the ifelse function. This is a vectorized function that behaves just as an if-else-expression: compare <- function(x, y) { ifelse(x < y, -1, ifelse(y < x, 1, 0)) } compare(1:6, 1:3) ## [1] 0 0 0 1 1 1 The situation is not always so simple that we can replace if- statements with ifelse. In most cases, we can, but when we cannot, we can instead use the function Vectorize. This function takes a function that can operate on single values and translate it into a function that can work component-wise on vectors. As an example, we can take the compare function from before and vectorize it: compare <- function(x, y) { if (x < y) { -1 } else if (y < x) { 1 } else { 0 } }
36.
compare <- Vectorize(compare) compare(1:6,1:3) ## [1] 0 0 0 1 1 1 By default, Vectorize will vectorize on all parameters of a function. As an example, imagine that we want a scale function that doesn’t scale all variables in a vector by the same vector’s mean and standard deviation but use the mean and standard deviation of another vector: Scale_with <- function(x, y) { (x - mean(y)) / sd(y) } This function is already vectorized on its first parameter since it just consists of a vectorized expression, but if we use Vectorize on it, we break it: scale_with(1:6, 1:3) ## [1] -1 0 1 2 3 4 scale_with <- Vectorize(scale_with) scale_with(1:6, 1:3) ## [1] NA NA NA NA NA NA The function we create with Vectorize is vectorized for both x and y, which means that it operates on these component-wise. When scaling, the function only sees one component of y, not the whole vector. The result is a vector of missing values, NA because the standard deviation of a single value is not defined. We can fix this by explicitly telling Vectorize which parameters should be vectorized—in this example, only parameter x: Scale_with <- function(x, y) { (x - mean(y)) / sd(y)
37.
} scale_with <- Vectorize(scale_with, vectorize.args="x") scale_with(1:6,1:3) ## [1] -1 0 1 2 3 4 Simple functions are usually already vectorized, or can easily be made vectorized using ifelse, but for functions more complex, the Vectorize function is needed. As an example, we can consider a tree data structure and a function for computing the node depth of a named node—the node depth defined as the distance from the root. For simplicity, we consider only binary trees. We can implement trees using lists: Make_node <- function(name, left = NULL, right = NULL) list(name = name, left = left, right = right) tree <- make_node("root", make_node("C", make_node("A"), make_node("B")), make_node("D")) To compute the node depth, we can traverse the tree recursively: node_depth <- function(tree, name, depth = 0) { if (is.null(tree)) return(NA) if (tree$name == name) return(depth) left <- node_depth(tree$left, name, depth + 1) if (!is.na(left)) return(left) right <- node_depth(tree$right, name, depth + 1) return(right) } This is not an unreasonably complex function, but it is a function that is harder to vectorize than the scale_with function. As it is, it
38.
works well forsingle names: node_depth(tree, "D") ## [1] 1 node_depth(tree, "A") ## [1] 2 but you will get an error if you call it on a sequence of names: node_depth(tree, c("A", "B", "C", "D")) It is not hard to imagine that a vectorized version could be useful, however. For example, to get the depth of a sequence of names: node_depth <- Vectorize(node_depth, vectorize.args = "name", USE.NAMES = FALSE) node_depth(tree, c("A", "B", "C", "D")) ## [1] 2 2 1 1 Here, the USE.NAMES = FALSE is needed to get a simple vector out. If we did not include it, the vector would have names based on the input variables. See the documentation for Vectorize for details. Infix Operators Infix operators in R are also functions. You can overwrite them with other functions (but you really shouldn’t since you could mess up a lot of code), and you can also make your own infix operators. User-defined infix operators are functions with special names. A function with a name that starts and ends with % will be considered an infix operator by R. There is no special syntax for creating a function to be used as an infix operator, except that it should take two arguments. There is a special syntax for assigning variables, though, including variables with names starting and ending with %.
39.
To work withspecial variables, you need to quote them with backticks. You cannot write +(2, 2) even though + is a function. R will not understand this as a function call when it sees it written like this. But you can take + and quote it, `+`, and then it is just a variable name like all other variable names: `+`(2, 2) ## [1] 4 The same goes for all other infix operators in R and even control structures: `if`(2 > 3, "true", "false") ## [1] "false" The R parser recognizes control structure keywords and various operators, for example, the arithmetic operators, and therefore these get to have a special syntax. But they are all really just functions. Even parentheses are a special syntax for the function `(`, and the subscript operators are as well, `[` and `[[`, respectively. If you quote them, you get a variable name that you can use just like any other function name. Just like all these operators have a special syntax, variables starting and ending with % get a special syntax. R expects them to be infix operators and will treat an expression like this: exp1 %op% exp2 as the function call `%op%`(exp1, exp2) Knowing that you can translate an operator name into a function name just by quoting it also tells you how to define new infix operators. If you assign a function to a variable name, you can refer to it by that
40.
name. If thatname is a quoted special name, it gets to use the special syntax for that name. So, to define an operator %x% that does multiplication, we can write `%x%` <- `*` 3 %x% 2 ## [1] 6 Here, we used quotes twice, first to get a variable name we could assign to for %x% and once to get the function that the multiplication operator, *, points to. Just because all control structures and operators in R are functions that you can overwrite, you shouldn’t go doing that without extreme caution. You should never change the functions the control structures point to, and you should not change the other operators unless you are defining operators on new types where it is relatively safe to do so. Defining entirely new infix operators, however, can be quite useful if they simplify expressions you write often. As an example, let us do something else with the %x% operator— after all, there is no point in having two different operators for multiplication. We can make it replicate the left-hand side a number of times given by the right-hand side: `%x%` <- function(expr, num) replicate(num, expr) 3 %x% 5 ## [1] 3 3 3 3 3 cat("This is ", "very " %x% 3, "much fun") ## This is very very very much fun We are using the replicate function to achieve this. It does the same thing. It repeatedly evaluates an expression a fixed number of times. Using %x% infix might give more readable code, depending on your taste.
41.
In the interestof honesty, I must mention, though, that we haven’t just given replicate a new name here, switching of arguments aside. The %x% operator works slightly differently. In %x%, the expr parameter is evaluated when we call replicate. So if we call %x% with a function that samples random numbers, we will get the same result repeated num times; we will not sample num times. rnorm(1) %x% 4 ## [1] -0.8094755 -0.8094755 -0.8094755 -0.8094755 Lazy evaluation only takes you so far. To actually get the same behavior as replicate, we need a little more trickery: `%x%` <- function(expr, num) { m <- match.call() replicate(num, eval.parent(m$expr)) } rnorm(1) %x% 4 ## [1] 0.8430961 -2.9336330 -1.1009706 0.2947148 Here, the match.call function just gets us a representation of the current function call from which we can extract the expression without evaluating it. We then use replicate to evaluate it a number of times in the calling function’s scope. If you don’t quite get this, don’t worry. We cover scopes in a later chapter. Replacement Functions Another class of functions with special names is the so-called replacement functions. Data in R is immutable. You can change what data parameters point to, but you cannot change the actual data. Even when it looks like you are modifying data, you are, at least conceptually,
42.
creating a copy,modifying that, and making a variable point to the new copy. We can see this in a simple example with vectors. If we create two vectors that point to the same initial vector, and then modify one of them, the other remains unchanged: x <- y <- 1:5 x ## [1] 1 2 3 4 5 y ## [1] 1 2 3 4 5 x[1] <- 6 x ## [1] 6 2 3 4 5 y ## [1] 1 2 3 4 5 R is smart about it. It won’t make a copy of values if it doesn’t have to. Semantically, it is best to think of any modification as creating a copy, but for performance reasons, R will only make a copy when it is necessary—at least for built-in data like vectors. Typically, this happens when you have two variables referring to the same data, and you “modify” one of them. We can use the address function to get the memory address of an object. This will change when a copy is made but will remain the same when it isn’t. And we can use the mem_change function from the pryr package to see how much memory is allocated for an expression. Using these two functions, we can dig a little deeper into this copying mechanism. (The exact output will depend on your computer, but you should see something similar to what is shown as follows.) We can start by creating a longish vector and modifying it:
43.
library(pryr) rm(x) ; rm(y) mem_change(x<- 1:10000000) ## 2.31 kB address(x) ## [1] "0x7fe426826a90" mem_change(x[1] <- 6) ## 80 MB address(x) ## [1] "0x7fe420000000" When we assign to the first element in this vector, we see that the entire vector is being copied. This might look odd since I just told you that R would only copy a vector if it had to, and here we are just modifying an element in it, and no other variable refers to it. The reason we get a copy here is that the expression we used to create the vector, 1:10000000, creates an integer vector. The value 6 we assign to the first element is a floating point, called “numeric” in R. If we want an actual integer, we have to write “L” (for “long” integer) after the number: class(6) ## [1] "numeric" class(6L) ## [1] "integer" When we assign a numeric to an integer vector, R has to convert the entire vector into numeric, and that is why we get a copy:
44.
z <- 1:5 class(z) ##[1] "integer" z[1] <- 6 class(z) ## [1] "numeric" If we assign another numeric to it, after it has been converted, we no longer get a copy: mem_change(x[3] <- 8) ## -1.14 kB address(x) ## [1] "0x7fe420000000" All expression evaluations modify the memory a little, up or down, but the change is much smaller than the entire vector, so we can see that the vector isn’t being copied, and the address remains the same. If we assign x to another variable, we do not get a copy. We just have the two names refer to the same value: mem_change(y <- x) ## 376 B address(x) ## [1] "0x7fe420000000" address(y) ## [1] "0x7fe420000000"
45.
If we changex again, though, we need a copy to make the other vector point to the original, unmodified data: mem_change(x[3] <- 8) ## 80 MB address(x) ## [1] "0x7fe430000000" address(y) ## [1] "0x7fe420000000" But after that copy, we can again assign to x without making additional copies: mem_change(x[4] <- 9) ## 112 B address(x) ## [1] "0x7fe430000000" When you assign to a variable in R, you are calling the assignment function, `<-`. When you assign to an element in a vector or list, you are using the `[<-` function. But there is a whole class of such functions you can use to make the appearance of modifying an object, without actually doing it of course. These are called replacement functions and have names that end in <-. An example is the `names<- ` function. If you have a vector x, you can give its elements names using this syntax: x <- 1:4 x
46.
## [1] 12 3 4 names(x) <- letters[1:4] x ## a b c d ## 1 2 3 4 names(x) ## [1] "a" "b" "c" "d" There are two different functions in play here. The last expression, which gives us x’s names, is the names function. The function we use to assign the names to x is the `names<-` function. Any function you define whose name ends with <- becomes a replacement function, and the syntax for it is that it evaluates whatever is on the right-hand side of the assignment operator and assigns the result to the variable that it takes as its argument. So this syntax names(x) <- letters[1:4] is translated into x <- `names<-`(x, letters[1:4]) No values are harmed in the evaluation of this, but the variable is set to the new value. We can write our own replacement functions using this syntax. There are just two requirements. The function name has to end with <- —so we need to quote the name when we assign to it—and the argument for the value that goes to the right-hand side of the assignment has to be named value. The last requirement is there, so replacement functions can take more than two arguments. The `attr<-` function is an example of this. Attributes are key- value maps that can be associated with objects. You can get the attributes associated with an object using the attributes function
47.
and set allattributes with the `attributes<-` function, but you can assign individual attributes using `attr<-`. It takes three arguments, the object to modify, a which parameter that is the name of the attribute to set, and the value argument that goes to the right-hand side of the assignment. The which argument is passed to the function on the left-hand side together with the object to modify: x <- 1:4 attributes(x) ## NULL attributes(x) <- list(foo = "bar") attributes(x) ## $foo ## [1] "bar" attr(x, "baz") <- "qux" attributes(x) ## $foo ## [1] "bar" ## ## $baz ## [1] "qux" We can write a replacement function to make the tree construction we had earlier in the chapter slightly more readable. Earlier, we constructed the tree like this: tree <- make_node("root", make_node("C", make_node("A"), make_node("B")), make_node("D")) but we can make functions for setting the children of an object like this:
48.
`left<-` <- function(node,value) { node$left = value node } `right<-` <- function(node, value) { node$right = value node } and then construct the tree like this: A <- make_node("A") B <- make_node("B") C <- make_node("C") D <- make_node("D") root <- make_node("root") left(C) <- A right(C) <- B left(root) <- C right(root) <- D tree <- root To see the result, we can write a function for printing a tree. To keep the function simple, I assume that either both children are NULL or both are trees. It is simple to extend it to deal with trees that do not satisfy that; it just makes the function a bit longer: print_tree <- function(tree) { build_string <- function(node) { if (is.null(node$left) && is.null(node$right)) { node$name } else { left <- build_string(node$left) right <- build_string(node$right) paste0("(", left, ",", right, ")") } }
49.
build_string(tree) } print_tree(tree) ## [1] "((A,B),D)" Thisfunction shows the tree in what is known as the Newick format and doesn’t show the names of inner nodes, but you can see the structure of the tree. The order in which we build the tree using children is important. When we set the children for root, we refer to the variable C. If we set the children for C after we set the children for root, we get the old version of C, not the new modified version: A <- make_node("A") B <- make_node("B") C <- make_node("C") D <- make_node("D") root <- make_node("root") left(root) <- C right(root) <- D left(C) <- A right(C) <- B tree <- root print_tree(tree) ## [1] "(C,D)" Replacement functions only look like they are modifying data. They are not. They only reassign values to variables.
that the letterfrom home contained something of more striking import than the warning against pernicious fevers. The intelligence which disturbed him was conveyed on the last two sheets, and this was how it ran:— "I know you will be grieved to hear that your uncle Dick is dead. Since your father was drowned I have never had a line from him; he was the first to bring the sad news to me, and his own sorrow seemed greater than he could bear. Your father and he had been inseparable companions in their youth, and many times before the Sea King sailed on her last cruise I used to hear them planning out their great schemes for the future, for your uncle had ever been a wanderer, and was filled with strange ideas about the riches of some parts of the world he had visited. He went off to Australia after arranging your poor father's affairs, and nothing was ever heard of him again. All along I fancied that it was his money which provided the little income left to us, for you father's savings could not have been much; sailors are so poorly paid. The solicitors always put me off when I inquired about it, but now I know that it was his great kindly heart which went out to the widow and the fatherless, and caused provision to be made for them out of his own scanty means. On the morning after you left I received a letter from a gentleman who had just returned from Australia, and who had been with him when he died, enclosing a draft for two hundred pounds, and saying that that was the sum realized by the sale of your uncle's effects, and that he had been entrusted to send it to me. No other information was given, and no address was on the letter. When I showed it to my solicitors they told me the truth of what I had guessed from the first. My boy, you were always uncle Dick's favourite, and you have every cause to remember him gratefully. If you can find out where he died, erect a little cross over his resting- place for me. I would so much like to have it done." Bob read and re-read the strange story which brought back the past so vividly to his mind, and his eyes grew moist in spite of himself. "No bad news, I hope, lad," spoke Mackay, kindly.
52.
Bob struggled withhis emotion for a moment without success, then handed the pages to his interrogator in silence. Mackay read them over carefully, with a face showing keen concern; indeed, he seemed even more moved than Bob when he had finished. "Ay, ay," he said huskily, "he was a good man, an' there's too few o' his sort in the world. But you'll dae what your mother bids you. You will put up that cross afore you leave Australia. I'll—I'll help you to find the place." Then he turned abruptly to Jack, who had read his letter, and was now gazing at the envelope with profound content. "You've been gloatin' over your billy doo for some time, Jack," he said lightly. "I don't suppose your news has affected your appetite." Jack flushed, and made haste to secrete his precious missive; but in his hurry the envelope fell to the floor, and it was observed that it bore the same peculiar postmark as Bob's. The boy grabbed it up in confusion, while the big man laughed. Whereupon Jack waxed indignant. "What about your own billet-doux?" he asked mischievously. "I think I noticed you got a letter too." "Here it is, young Lochinvar, here it is," and Mackay flung an open sheet at the youth. "Read it, read it; don't mind me. I'm sort o' pleased to mak' it known that somebody thinks o' me." Obeying his request, Jack cleared his throat and read aloud the following:— "Dear Mr. Mackay.— "I have just heard that you are about to start out on a journey into the interior, and I thought I would remind you of a little account I have against you for several items you sent for last week. The amount is £10 17s. 6d. I'll let you off the odd sixpence, but please send your cheque for the remainder before you start. The Never Never is such an uncertain country—to get out of. Best wishes.
53.
"Yours sincerely, "J. Rannigan." "Now,that is what I call a thoughtful letter," commented Jack, when he had finished. "A vera thoughtful letter indeed," agreed Mackay, dryly. Then they set about preparing tea, and while they were thus engaged the Shadow made his appearance, evidently in great good humour. He carried something concealed in his hand which he gazed at tenderly as he entered, then consigned it to some secret recess in his scanty wardrobe. "I reckon," said he, "that I want an invite to your banquet to-night. I hasn't even an inch o' damper left in my tent. I broke up the happy home too soon, I calc'late." Mackay laughed. "I ken you're a grand cook, Shadow," said he, "an', providin' ye behave, we'll be glad to have your company. Ye'll get flour in that bag at your feet, an' water in the kerosene-tin beside ye. Now ye can take my place an' mak' wi' these ingredients something nice an' tasty. I'll even gie ye a tootle on the flute to inspire ye in yer efforts." The lad's countenance fell. "I see I has come along too soon," he grumbled. Then he fished about in the folds of his shirt and drew forth the treasure he had secreted. In the quickly fading light it was not easily observable what he held in his hand; but when the wondering trio saw him convey the same to his mouth their worst fears were realized. Before they could protest, the wailing of a mouth-organ filled the tent. The Shadow blew with might and main, an ecstatic joy illuminating his features, his foot keeping time to the music he perpetrated, and sending up clouds of dust from the sandy floor. That he anticipated a sudden closure was very apparent by the fierce energy he displayed, yet, strangely enough, he was allowed to finish the first tune without mishap; it was only when he adroitly essayed to glide off into a fresh outburst that Mackay intervened.
54.
"Ye should playthat first spasm mair pianissimo," he ventured mildly, while Jack sprinkled water about to allay the dust. "Now, put that orchestra in your pocket, an' keep it there until we get far oot into the bush. Then ye can kill the crows wi' it if ye like." "Right O!" responded the Shadow, seemingly delighted to have escaped so easily. "Now, I reckon I'll bake a real bowser brownie for tea, an' we'll have a real ole blow out, we will." "Let us eat, drink, and be merry," remarked Bob, thoughtfully, "for to-morrow we——" "Start for the Never Never," prompted Jack. Shortly after sunrise the camel team was once more loaded up, and now Fireworks' demeanour was beyond reproach; he submitted to his burden with philosophic calm, and only once showed his playful disposition by tearing the sleeve from Emu Bill's shirt while that gentleman was standing too conveniently near his head. By eight o'clock all was ready for the start, the last breakfast in camp had been partaken of, and the various members of the expedition were standing at their posts awaiting the signal for advance. The population of Golden Flat had turned out en masse to witness the departure. It was not every day that an expedition left for the distant Never Never. Nuggety Dick and Dead Broke Dan were there looking anything but happy; one word from Mackay even now would have made them join the party but the leader of the expedition sternly refused to meet their appealing eyes. Once more he glanced over the team critically, as if mentally weighing up the amount of endurance contained in the four powerful animals. His scrutiny seemed to give him much satisfaction, and he smiled grimly as he turned his face to the east. "All ready, boys?" he cried. "All ready!" came the unanimous reply.
55.
Then, just ashe was about to signal "Right away," the crowd parted, and Macguire struggled to the front. "Hold on a minute, boys!" he shouted. "I want a word with Mackay." As for Mackay, he viewed the interrupter with considerable disfavour. "If you had any differences to settle, you might have come along last night," he said. "What's the trouble wi' you?" "Why, man, I just want to say that I bear no ill feeling, an' that I hope you'll be successful, that's all. What course are ye making?" Mackay gazed at the questioner in puzzled wonderment. "I'm glad to have your good wishes, Macguire," he said slowly. "Our course is east by north to a place that's a bit harder to find than Golden Flat. Let her go, boys!" The long whips cracked, Misery's bell began to chime; the crowd stepped back to give the ponderous team free passage, uniting as they did so in a stentorian Coo-ee, that strange call of the bush which combines in its notes the acme of feeling and good fellowship. Bob and Jack coo-eed lustily in return, Mackay waved a cheery goodbye, Emu Bill and Never Never Dave chaffed their sorrowing acquaintances with tender affection as they passed along the line, and the Shadow, pulling at Fireworks' nose-rope with one hand contrived to unearth his mouth-organ with the other. Strongly he blew, and stepped forth jauntily to the stirring time of "The Girl I left Behind Me," but his charge steadfastly refused to accelerate his gait in such undignified fashion, and the Shadow had perforce to seek around in his répertoire for a more suitable march, which he soon found in "There is a Happy Land," and he kept up his melancholy dirge until he heard Never Never's voice raised in dire threat against his person. Then there was silence, broken only by the tinkling bell of the leading camel, and the vague echoes of Golden Flat's farewells.
56.
Thus they headedout towards the desert, into the land of the Never Never.
57.
CHAPTER X An AwkwardPredicament The first halt was made at noon when little more than eight miles had been traversed. The country encountered from the start had been a soft powdery sand formation, with occasional belts of dwarfed eucalypti, which intervened from the north. Progress was necessarily slow at this early stage of the journey, for it was advisable to allow the camels to harden to their work gradually. Mackay had so far led the march, steering an approximate course by the sun, but immediately they stopped, he called Bob aside for a conference. "You see," he said, "when we went out before we started from a more northerly latitude, an' I calculate we should hit our old track in another hundred and eighty miles if we keep angling in a wee bit north o' east. I've got a copy o' the log up to pretty near the—the finish, an' here's where I think we ought to join on to Bentley's route." He unfolded a long track chart which he carried in his hand; it was made up of several sheets of ordinary note-paper, gummed laterally together, and on its much faded surface several inky hieroglyphics stood out bravely. He pointed to a besmeared cross nearly halfway over the chart, and Bob, looking closely, read the printed lettering beside it: "Fortunate Spring, lat. 28° 17´ 5´´, long. 125° 19´ 6´´."
58.
"HE UNFOLDED ALONG TRACK CHART WHICH HE CARRIED IN HIS HAND" "We are somewhere under the twenty-fifth parallel just now," reflected Bob. "That means we are about 120 miles south of your old
59.
track. I'd betterdraw out our present position on my own chart and mark a compass course for Fortunate Spring." Mackay looked relieved. "Be vera exact wi' your calculations, my lad," he said earnestly, as he walked away. Bob took the sun's altitude three times while a hasty lunch was being prepared, and laboriously checked each result to five places of decimals, then he carefully marked their temporary camp's position on his still bare chart, and drew a dotted line thence to the location of Fortunate Spring. "We'll have to travel nor'-east half north to make it," said he. Mackay nodded cheerfully. "I hope we are lucky in strikin' water," he observed. "About ten days is our stretch without it, for the camels can't stand more, and they can't stand that often either." "We'll hit it right enough," commented Emu Bill, hopefully. "If it's in the country, you kin bet I'll smell it," grunted Never Never. "I'm strong at nosin' out water, I am." "Oh, after that one hundred and eighty miles, I'll know where we are," said Mackay; "but there's always some little uncertainty as we understood from the first, an' it won't be outside o' our calculations if we do go thirsty a bit." "Not a blessed fraction!" cried the Shadow, decanting the boiling tea from the billy into the enamelled cups. "Who says sugar? You, Emu? Well, there ain't none; have a try at saccharine, an' be happy." He gulped down his own portion hurriedly, then ran off to round up Fireworks, which was beginning to stray too far from his neighbours, and ten minutes later the expedition was once more on the move. The next several days passed uneventfully; the same uninspiring desert sands prevailed, and the intense heat haze radiating from its shimmering surface affected the eyes of the travellers, causing them to quiver and blink painfully, while overhead the sun stared down
60.
from a cloudlesssky. Not a trace of moisture was visible anywhere, certainly no water could exist amid these barren wastes, and all hoped most anxiously that a change in the monotonous landscape might soon take place. "It's a pretty thirsty lookin' start we've made," said Mackay, when a week had elapsed, and they still struggled along ankle deep in the burning sands. Bob was walking by his side keeping an eager eye on what appeared to be a light cloud-patch on the far horizon. He had noticed it for some time, but was unwilling to mention his hopes in case they might be doomed to early disappointment. Now, however, he felt pretty sure that his eyes had not deceived him. "There's a belt of timber straight ahead," he announced quietly, after Mackay had spoken. The elder man shifted his gaze somewhat, and with puckered eyes surveyed the slight break on the horizon's even curve. "You're quite richt, Bob," he remarked, with a sigh of relief. "I've been steerin' by the shadow o' the sun across the camels, an' I've almost mesmerized mysel', I think, or I should have seen those trees earlier. It's a hard course for a bushman, Bob, that fractional nor'- easter you gave me." Emu Bill and Never Never Dave had by this time found it necessary to assist in pulling the camels through the sand. Jack, leading Misery, had not much difficulty with his charge, for that wiry animal plodded steadily onward with ponderous movement despite all obstacles, but Fireworks was by no means as energetic as he once was, and the Shadow anathematized him roundly as he, with bent shoulders, strained at the nose-rope of the reluctant beast, a proceeding which the two bushmen had soon to emulate. Now, when these weary individuals heard of the impending change in the land surface, they gave vent to their joy in sundry whoops of delight. "It looks likely country for water, Mac," cried Never Never, as they drew nearer, and could plainly distinguish the feathery scrub in their
61.
course. The sandtoo as they advanced, hardened considerably, and here and there great dioritic blows reared their heads above the plain. "You're right there, Dave," responded Mackay, after a while, "if there's been any rain in the district for the last year or two we ought to find a rock hole—Hillo! Easy boys, and get your rifles ready. I see a wheen niggers dodgin' aboot among the scrub." "Nigs!" echoed Emu Bill and Never Never almost with one voice. There was an inflection of decided pleasure in the exclamation, as if these two had longed for a skirmish to ease the routine of their journey. Mackay himself seemed in no way displeased, yet he took care to impress caution on his impetuous associates. "A spear or boomerang can kill as well's a bullet," he warned, while each man examined his rifle. "Now, Jack, don't be so anxious to get forrit, an' keep on the lee side o' Misery an' no' at his head when we get near." As yet Bob was unable to distinguish any aborigines among the sparse scrub, but as they continued their wary advance he soon perceived several dusky forms crouching amid the timber, and his heart gave a bound when the savage creatures suddenly stood up and united in a shrill yell of defiance. He had never dreamt that these wild denizens of the bush could be so hideous; they seemed more ape than man, their faces were covered by long tangling hair black as jet, and only white gleaming eyes were visible; their bodies were repulsively scarred and painted. This much Bob had time to notice, then a hail of spears rustled out from the scrub, fell short, and buried their barbed tips in the sand at their feet. And now the bush seemed alive with blacks; uncouth forms sprang from the side of each tiny sapling where they had been standing motionless, and harsh guttural screams filled the air. "They're a bit more numerous than I thought," muttered Mackay, calling a halt, "an' I've an idea that if we dinna rush them pretty quick, they'll rush us. Now, Jack, swing Misery round an' let him
62.
stand, then grabyour rifle." Jack obeyed promptly, and at that moment another shower of spears hurtled overhead. "By gum!" growled Never Never, "they'll get our range next try." "They're comin' for us now, I reckon!" cried the Shadow, and of that there could be no doubt; the shrieking horde had evidently decided to exterminate the invaders of their domain without further delay. On they came, brandishing their waddies and boomerangs, a compact mass of blood-thirsty black fury. "Now, boys!" roared Mackay, "Aim low and stop them." A thunderous discharge followed his words, and six rifles spat out their leaden challenge to the foe. The wonderful din created by the exploding cordite apparently stupefied the blacks for a moment; they ceased their wild rush, and gazed with astonishment at those of their number who had fallen. Despite Mackay's oft-repeated animosity towards the aborigines in general, he could not countenance wholesale slaughter. "They're a poor lot, boys," said he; yet even while he commiserated with them the savages joined in another determined rush. There must have been over twenty of them, and so impetuously did they come that they were within twenty yards of the white defenders before a second volley made them hesitate, and even now they did not all stop; a few stalwart warriors kept on their mad course, and hurled themselves almost upon the reeking rifle muzzles. If the attack had been made in full force things would have gone hard with the expedition. As it was, however, the little group had no difficulty in beating back the frenzied band. The Shadow and Jack were in their element; they little recked of danger when plying their heated weapons, though the vengeful club of one of the natives had missed Jack's head by little more than a hair's breadth, and the Shadow's face had been severely gashed by a flying boomerang. Bob could not fail to observe how serious matters would have been had the natives made their onrush in skirmishing order; their close blocked formation made it impossible for even the most random shots to miss their billet, and now as the savage and
63.
discomfited creatures sullenlywithdrew, they dragged with them many maimed and wounded comrades. "I can't understand why the beggars are so stupid," said Bob, watching the last of them disappear in the distance. "Ye may learn more o' their tactics before our journey is finished," Mackay observed quietly; "at the same time, there is a wonderful difference among the tribes, an' that is where the explorer's danger lies. He may judge from a nomadic spiritless lot which he may chance to meet that a' natives are the same, and he may gie his life for the mistake later on." By this time the team was again on the move, and within a few minutes a halt was made in the densest part of the scrub, while Never Never and Emu Bill searched around for water. But the search was vain, no welcome spring or rock-hole could be found, and a heavy gloom began to affect the spirits of the party whose hopes had been raised so high only to be thus rudely dashed. Even Mackay, usually most cheerful in times of stress and danger, looked grave as he reflected upon their somewhat unenviable position. He knew what the others had not calculated upon. He knew that the camels were already at their last extremity of endurance; accustomed as they had been while at Golden Flat to drink every few days, they had not absorbed their full supply before starting. Misery alone, hardened veteran of many desert journeys that he was, had drunk his fill, and now his great reserve of strength showed plainly over the other beasts. "I reckon them nigs had a mighty cheek to make such a howlin' fight for nothin'," complained the Shadow. "One would have thought they was protectin' a lake o' cool crystal water——" "Slow up on that, Shad, or I'll squelch ye wi' an empty water-bag," warned Emu Bill, who could not stand reference to such an unlimited supply of the precious fluid at this moment.
64.
"There must bewater about, all the same," said Bob. "These natives, I suppose, get thirsty, like other people. I'm off to have a look round myself," and he sped away. "Be vera careful, Bob, be careful——" But Bob was already out of earshot, pursuing a dogged course eastward in the wake of the retreating blacks. In his hand he grasped a heavy Colt revolver, which he had extricated from the holster on his belt. A wild idea had seized him; he meant, if possible, to capture one of the blacks and make him disclose the treasure they had guarded so fiercely. It was a foolhardy plan which had so hastily formulated in his brain, and in his calmer moments Bob would have been quick to realize what a desperate venture was that which he had now so lightly undertaken. But the urgent necessity of finding water was powerfully impressed upon him, and caution for the time being was thrown to the winds. Eagerly he rushed along, and in a few minutes had passed out of sight of his companions; then suddenly two ebony-skinned warriors barred his path; he had blundered right on to them by the merest accident. At a glance he saw that they were armed with waddies and boomerangs only, their spears having probably been discharged in the fray from which they had fled. Yet a waddie at close quarters is no mean weapon, and Bob pulled himself up promptly, and with a stern smile levelled his revolver. His astonishment was great when, with a curious gurgle of mingled surprise and fear, the dusky twain dropped their weapons and incontinently fled before him. And now Bob's heart was filled with wrath because of the cowardice of the pair. Had they only waited and surrendered quietly to his request—though how he could have made them understand his wishes he did not stop to think—all might have been well. With scarce a pause he gave chase, covering the ground in long impetuous strides, but it soon became evident that unless something unforeseen occurred to check the flight of the fugitives, he could never hope to overtake them. On they sped, clearing the sand in great bounds, even stopping at intervals to gaze back at their pursuer. Bob's chagrin was deep, and he sent one or
65.
two revolver bulletscrashing after the disappearing couple which had the effect of making them run the faster, while far in the rear the excited cries of his anxious comrades showed that they were now concerning themselves over his prolonged absence. Yet the ardour of the pursuit had taken possession of Bob; with a mighty effort he managed to quicken his pace so that he actually drew up considerably on the fleet-footed pair—scarce fifty yards divided them. "Another spurt and I've got them," thought Bob, and he clenched his teeth and strove boldly in the attempt. Now thirty yards only separated them, now twenty, now ten. Bob chuckled grimly to himself at the prospect of after all being successful in the chase, and stretched out his hand, then in an instant the hitherto level course came to an abrupt stop, a layer of branches and spinifex grass spread right across the track. The blacks had cleared it at a leap, but before Bob had time to prepare for a spring he had staggered into the midst of the cut brushwood, and at once felt himself sinking down into space. It all occurred in a second or so. He clutched wildly at the pigmy branches as he descended through them, but they broke in his hands, and with a rush and a plunge he fell downwards into an unknown depth. When he recovered himself, about a minute later, he became aware that he was standing, considerably shaken and bruised, waist deep in some semi-solid fluid at the bottom of a natural shaft, which he mentally calculated to be at least twenty feet deep. He had found water for a surety, and now would have given much to get out of its slimy embrace, but the steep dioritic walls were quite unscalable. Bob was hopelessly a prisoner. Then did he blame himself most bitterly for his mistaken ardour and lack of perception. The wily natives had but pretended to be overcome at the last wild rush so as to lead him directly over the subterranean trap. "Mackay was certainly right," he muttered. "Their cunning is nothing short of devilish; and after being told of that, here I go like a fool and prove it for myself."
66.
He had littletime, however, for unprofitable moralizings, and he peered up and around his strange prison-house with anxious eyes, yet his surroundings were of so murky a nature that he could only vaguely guess the description of the trap into which he had fallen. His gaze was instinctively directed toward the gaping hole in the brushwood through which he had fallen, though what he expected to see there he did not very well know. But he now realized the nature of the blacks too fully to believe for a moment that they intended to leave him to his fate without further molestation. "Why, the water is bad enough as it is," he said, with a forced attempt at pleasantry. "They'll certainly come to fish me out before long." He had not been in his awkward predicament many minutes when a black grinning face stared down at him. Bob shuddered and crouched closer to the damp rocks; he was half prepared for a stone to be thrown or a spear to be poked tantalizingly in his direction, but no such proceedings were taken. The demoniacally leering face continued to look down at him without movement for several seconds, when it was joined by another equally hideous; they belonged to the two savages who had led him such an unfortunate chase. They had now returned to view their victim after having probably given the alarm to their fellows. Bob groaned in dismay, but returned their gaze with stoical complacency, having not yet fully comprehended his true position. At length, however, his strange gaolers, with many guttural exclamations, began to cover up the tell-tale gap in the layer of furze; then their prisoner's senses returned to him with a rush, and his emotions almost overwhelmed him. The blacks surely meant to cover up the hole so that his companions might not find him, and when they would depart after vain searchings, he would be left to the tender mercies of the "stupid" natives he had so commiserated! In truth Bob's cup of bitterness was filled to overflowing.
67.
But he decided,nevertheless, to do his best to prevent the success of their scheme. His revolver was still dry, for he had by some odd instinct clung to it tenaciously despite his demoralizing downfall, and now he became aware for the first time that he held it in his hand. He fired two shots upwards in rapid succession. Operations ceased on the instant, and Bob felt comforted. He knew that Mackay would soon seek him out if any clue as to his whereabouts was left. His rejoicings, however, were premature, and very speedily checked. As he gazed at the sky through the gap which gave him light, he noticed the aperture slowly yet surely grow narrower and narrower. The blacks were pushing the superfluous brush over the opening by the aid of long sticks! Bob shouted with the full force of his lungs and discharged the remaining shots in his revolver upwards, but only a hoarse cackle of satisfaction from the natives answered his attempts at communication with the outside world, and soon—as the last glimpse of sky was shut out—he was enveloped in absolute darkness. "Well, I assuredly could not have landed myself in a worse fix if I had tried," he soliloquized with wonderful calm. "Here I am, shut up in a twenty-feet water-hole in the middle of the Australian desert and surrounded by hostile savages. That's pretty good for a start— and, I'm afraid, for a finish too." He continued his unpleasant musings, while he carefully reloaded his revolver. Then he wondered what his companions would do when he failed to appear, and a ray of hope flashed across his sorely tried brain. Mackay and Emu Bill were expert bushmen, and indeed so was Never Never Dave. He had often heard them speak of tracking up clues of even the very flimsiest nature; might they not, after all, be able to follow the slight impressions left by his footsteps on the sandy gravel?... What a cruel irony of Fate to plunge him headlong into what he most desired to find—water. Had he been caught in a sand-hole he would not have felt so much aggrieved; but water, of all things! While thinking in this strain, he remembered that, though he had been extremely thirsty all day, he had not yet tasted of his find. But his thirst had effectually gone from him, and he abhorred the slimy touch of the
68.
fluid which encircledhis limbs. Suddenly he felt some huge creature brush against his knee, and then climb up against him with many a wriggle and splutter. What new horror was this? Bob was anything but timid in temperament, yet he shivered at the sinuous contact of this unknown thing, and endeavoured frantically to shake it off, but it only clung the tighter. Some little time now elapsed, to Bob it seemed like half an hour, for the moments dragged like ages, though five minutes would have been a nearer estimate. Then a subdued muttering was heard above, and he expected every instant to see more hideous faces grinning at him through the bushy covering. He guessed that the whole tribe had now arrived to witness his plight; and he was not far wrong, for nearly all the warriors whose powers of locomotion had not been interfered with earlier in the day had assembled overhead. The weary sojourner in the depths kept his gaze fixed on the roof of the shaft where one or two gleams of light filtered through the last unevenly laid scrub; his eyes had by this time grown accustomed to the gloom of his environment, and while he watched he carefully cocked his revolver, and adjusted it to fire on the hair trigger, so that his aim might not be disturbed at a critical juncture. Soon a gaunt black hand drew aside the branches; Bob's haste was his own undoing. Had he waited long enough the oily-skinned savage might have let in the light more fully, but as it was he fired, and a howl of pain told him he had not fired in vain; but the brushwood fell back into position, and his prison was left as dark as ever. He now made an effort to climb up the walls of the dank and evil-smelling pit in which he was immured; but the flinty formations exposed were dripping with moisture, and slippery, and offered no place for foothold. Bob would have given much then for a match, there were a few in the pockets of his nether garments, but they were well submerged beneath the level of the water, and consequently useless. The floundering animal that had climbed against his legs next aroused his curiosity; he could not imagine what sort of creature it might be, and his courage was not sufficient to prompt his making a practical investigation as to its form or temper with his
69.
hand, which, asit afterwards turned out, was just as well for the hand. Another lull ensued, and he began to be alarmed at the silence of his dusky gaolers. Were they premeditating some sudden and novel doom for himself, or had they indeed abandoned him to die in this horrible water-trap? And where were his companions all the time? To relieve the monotony he fired two more shots upwards at random and was rejoiced to hear another yell of pain from outside, but a retaliation in the shape of a fusillade of stones came crashing down, missing him by a few inches only. Again he fired, and again. Bob had grown desperate, he did not much care what form the reply of the natives would take, but now he heard an answering shot in the distance, while near at hand the Shadow's well-known voice hilloed out lustily. There now appeared to be considerable agitation among the blacks above; their feet pattered on the sand confusedly, and then a shrill yell intimated to Bob clearly enough that his tormentors had taken flight. He was about to congratulate himself heartily on escaping so opportunely from a distinctly awkward predicament, when he heard the sand crunch under hurrying footsteps, and the Shadow, now close above, commenced to shout his name. He was evidently bent on following the retreating natives, for he halted not a moment, but kept up his mad rush forward. Before the horrified prisoner below could raise an alarm, he had jumped impetuously into the snare which had already done its work so well, and a moment later he tumbled down heavily head over heels by Bob's side. The spray he threw up almost blinded Bob, and the fetid odours that were thus again let loose, caused him to gasp wildly. His comrade in misfortune struggled to his feet with eloquent maledictions, and his amazement when he recognized Bob—the light was now streaming down through the gap he had made—was very genuine indeed. "What in thunder is you doing here?" he cried. Bob considered the question rather superfluous under the circumstances.
70.
"Me? Oh, I'mfishing!" he replied laconically. The Shadow ceased his flow of language for a moment, and examined the walls of his gloomy habitation with interest. It did not take him long to grasp the situation. "Hang it, that was a tidy trick to play on a peaceable sort o' cuss like me. They've bagged the pair of us, an' if we'd had the savvy o' a mosquito, we didn't oughter be here," he snorted in extreme disgust. "It is a bit humiliating," admitted Bob, not at all displeased that the wonderfully acute Shadow had blundered into the trap as easily as himself. It tended to soothe his wounded feelings in no little degree. "But all the same," he added brightly, "we've found water, and that's worth some inconvenience, isn't it?" The Shadow grunted something unintelligible and began to prospect in the almost viscous fluid with both hands. "There's some slimy crawler shoved up against me," he growled, "an' I reckon I'm goin' to break his little back, so that he won't have no appetite to feed on us afterwards." He groped around viciously. "I have had a good half hour of its company, whatever it is," remarked Bob. "But the splash you made frightened him off for a bit. But hold hard! Shadow, hold hard, man! Don't you see what it is?" Bob's eyes, more accustomed to the dull environment than his companion's, had now detected an unusually large-sized iguana struggling in the water; it had apparently fallen in from above, as they had done, and its snapping jaws looked decidedly dangerous. The Shadow ceased his investigations with remarkable celerity, then lifted up his voice in fluent condemnation of all sorts and conditions of crawling creatures. When he had exhausted his store of expletives, he made a vain effort to climb the oozy walls of the cavern, and succeeded only in getting a fresh douche for his pains.
71.
"I wonder who'llcome first," he murmured feebly, "Mackay or them savages? I reckon we shid know pretty sudden." They were not left much longer in doubt. The report of Mackay's powerful rifle broke the silence, they recognized it by the heavy charge of powder it fired and the series of shrill yells which answered it showed that the natives were still in the vicinity. Anon the anxious pair heard the scrub break before the advance of some hurrying person, and the crunch, crunch of feet in the sand. "Go back and mind the camels, Jack," they heard Mackay's decisive voice ring out. "I'll find Bob, if he's above ground, an' that reckless young rascal o' a Shadow too." "But we ain't above ground!" roared the last-named youth, forgetting that his voice would be absorbed in the echoes of the shaft before it reached the surface. On came the stalwart bushman, and the fierce invective against the blacks in general, and these savages in particular, which issued from his lips as he ran, came as a revelation to Bob, who had never heard his friend so moved. In a few moments he had reached the vicinity of the pit wherein the adventurous pair were entombed, and Bob made ready to signal once more with his revolver, but such action was unnecessary. The experienced eye of Mackay had quickly noticed the cut brushwood, and he bore down towards it without hesitation. Then, thrusting his head through the opening in the bushy covering, he surveyed the captives below with a grim smile of amusement. "So this is where you are, my lads," said he. His relief was so evident that Bob and the Shadow felt even more ashamed because of the trouble they had caused than there was any need for. Then Bob found his speech. "There's water here," he cried. "Water!" Mackay's ruddy features positively glowed with pleasure. "Well, well, I shouldna wonder but what you've taken the only means o' finding it, an' though it was a novel sort o' method, an' just
72.
a trifle dangerous,we canna be too thankful that it has succeeded. Now, you'll hae to content yoursel's a bit longer while I see aboot gettin' a rope to pu' ye up——" "Don't go away, boss!" howled the Shadow. "Them yelpin' baboons'll be back in two shakes if ye does." But Mackay had no intention of going away; he proceeded to signal with his rifle, and soon the entire camp, camels and all, arrived in answer to his call. Great was the hilarity of Jack and the two bushmen when they learned of the strange position in which Bob and the Shadow had been found; but their joy was real indeed that water had been discovered, after all, and when they raised their dripping comrades to the surface they embarrassed them more by their expressions of gratitude than by their display of what under the circumstances would surely have been but a pardonable levity. Now came the tedious process of drawing water for the camels to drink, and also for refilling the almost dry canvas bags which Remorse carried. For the latter purpose the thick sand-impregnated fluid was laboriously filtered through a sheet of calico, so that a fair amount of its solid matter was eliminated. But it was not the sediment that was the most objectionable feature of the liquid; it simply stank with vile odours, so that Emu Bill and Never Never Dave, who had undertaken the duty of hauling up the buckets, had anything but a pleasant time while they were so engaged. The boys marvelled at the extraordinary capacity of the camels for the uninviting solution; between them they managed to absorb well over a hundred gallons, and when at length they were satisfied, very little save mud remained at the bottom of the shaft. "I would never have believed these natives capable of such a smart trick as that they played on me," said Bob, who had been unusually silent since his rescue. "Imagine the forethought of the beggars in covering up that confounded hole, and then luring me directly on to it!"
73.
"They're no' sodeficient in gumption as you at first considered, Bob, my lad," answered Mackay, with a twinkle in his eye. "However, I don't think they covered up the shaft exactly for your benefit. Just look——" He kicked a few of the branches aside and drew Bob's attention to their wholly sapless nature. "These same bits o' twigs have done duty for many a long day. The natives cover the water principally to prevent evaporation as much as possible, but also to keep all sorts o' animals an' reptiles from fallin' into it an' so spoilin' the flavour. The water has vera likely lain in that rock-hole for years, an' only such judicious economy on their part has left us enough for our needs." "I reckon they'll have to shift their lodgings pretty soon," laughed the Shadow, "for they'll have a pretty hard job gettin' a drink when we leave, an' the next man that does a dive into the reservoir as Bob an' me did, shid strike something hard at the bottom." The afternoon was already far advanced, but when Never Never Dave suggested that they should camp where they were until morning, Mackay would not hear of such a proceeding. "We'll find trouble soon enough without lookin' for it, Dave," said he, "an' if there's one thing I dislike it's camping near a crowd o' niggers in the night time. They would try to swipe us out before morning, for the miserable vermin get vera brave after sundown. No, boys, we'll head out right now for Fortunate Spring. Fetch out the compass, Jack, an' let me have a look at that course again. The sun has shifted a bit since I worked out the correct shadow to steer by." Immediately afterwards Misery's bell began to chime, and the camel team moved on its weary way.
74.
CHAPTER XI The Findingof Fortunate Spring For several days after leaving the scene of Bob's adventure the travellers struggled over a most disheartening tract of country. The timber belt amid which they had discovered water proved to be but a narrow strip, extending down from the north-west; it evidently marked the course of an ancient river-bed, for immediately beyond its scope the sullen desert appeared bare of all vegetation, save for occasional clumps of saltbush and tufts of spinifex grass. Over this barren waste they forced their dogged course, starting at sunrise and halting towards noon, when the heat became too terribly oppressive both for man and beast; then in the evening they would continue the journey, sometimes marching late into the night. It was well for them that water had been found so opportunely, for assuredly none promised in the arid sands they were now encountering. The fifth day, however, brought with it the hope of better things. Away to the east the landscape took on a much more broken aspect, a feature which gradually extended right across the line of travel. Great dry gullies, starting from apparent nothingness, tore up the plain in all directions, and giant boulders of desert sandstone outcropped in prodigal profusion. And this drastic change in the land surface cheered the wanderers mightily, for though in itself it offered greater obstacles to progress than the weary sand- flats, it relieved the eyes, which had become so weary of gazing at the seemingly everlasting monotonous desert, and uplifted their hearts strangely. Another day, and several mouldering ridges surrounded them; mere hillocks of sand they were, yet, rising as they did abruptly from an even expanse, they appeared in the distance as precipitous mountain steeps, and it was hard to believe that their grandeur
75.
would fade awayat a closer view. Within these guarding barriers, a beautiful white tableland lay spread, so white and pure that it glittered like marble in the sun's rays. The sight was a dazzlingly splendid one, and Jack, who had been the first to climb the gentle elevation hiding the valley from the south, had exclaimed in delight — "What a huge lake we are coming to; it looks like a great frosted Christmas card!" "Lake!" Mackay had answered, almost sorrowfully. "Ay, it's a lake that will give us a maist desperate thirst, instead o' quenching what we've got." And soon the truth of this remark was borne painfully on them all, for the lake was a mass of crusted and crystallized salt, that crushed like tinder beneath their feet and showered over the heads of the voyagers in sparkling clouds of finest dust. It filled their ears and eyes and nostrils; they inhaled the minute grains with every breath; it covered their tattered clothing in a gauzy film of white. "Well, I'm blest!" ejaculated Emu Bill, "if this ain't the cruellest joke to play on a thirsty sinner, an' nary a drink within hundreds o' miles!" "Shut up, Bill, an' ye won't swallow so much of it," retorted Never Never Dave, unsympathetically. Then he was moved to further speech. "Bless yer soul! It's a whole brewery we'll want afore we gets through this, I'm thinking." "I had an idea," observed Mackay, blandly, "that you two had joined the temperance party a week or so before we left, so as to get accustomed to a bit o' a drought." "Temperance party!" stormed the unusually loquacious Never Never, "I reckon this here circus would break up any anti-thirst campaign in less'n five minutes." He would have continued, but his companion sternly rebuked him by casting at him the words with which he had himself been silenced.
76.
After that nota word was spoken for fully ten minutes, and the camel team staggered blindly on, floundering through intervening salt wreaths like ships in a heavy sea. The lake appeared to be nearly six miles in length, which meant that at least two hours would be spent in the crossing, for their rate of travel seldom exceeded three miles an hour, and was more often considerably less. In that time, if each man satisfied his craving for water from their very limited store, there would be but little left, and by Bob's calculations they were yet about thirty miles from the location of Fortunate Spring. But though each of the little party suffered severely, not one of them made other than jocular mention of his longing, and Mackay felt proud of the fortitude and reserve they displayed. He was especially concerned for Bob and Jack, for they, not having been hardened to such experiences, must have felt the influence of their salt bath most keenly; but if they were in any way incommoded they showed no sign. Bob walked by Mackay's side, talking at intervals concerning the probable geological history of interior Australia—a subject of endless interest to him. Jack and the Shadow strode at Misery's head, for now Fireworks needed no guiding hand at his nose-rope, but followed submissively in the rear of Repentance, and from snatches of their conversation, which floated to Mackay's ears, he gathered that Jack was giving his Australian comrade a description of the snows and frosts of the old country as a set-off to the blazing heat they were now experiencing. "Yes, I reckon I'll go home with you," the Shadow was saying. "It must be a grand country, wi' no snakes nor centipedes nor other crawlers, an' nary muskittie to nibble you in your sleep." Bob laughed. "I'm afraid the confined spaces at home would hardly suit him after this," he said. "I don't think I could stand the nature of things on the other side myself now." "Because you're a born wanderer, Bob," smiled Mackay; "an' the world itself will soon be too small for you."
77.
At last theend of the salt lake was reached, and cheerfully a path was forced over the encircling ridges, for all had high hopes of what might lie beyond. But disappointment again was their portion: the grim, unbroken desert stretched before them in all its hideous dreariness; the land of beau desire had not yet come. "I remember well," said Mackay, "that Fortunate Spring was in a pretty bare sort o' country, but it certainly wasna as bad as this, although we had a hard tussle before we came to it." On, on, they struggled; but, if anything, their course became more difficult as they proceeded. On the following morning a gentle wavy outline against the sky in the northerly distance warned them of some impending change, but by this time the members of the expedition had become spied to their comfortless lot, and scarce dared hope for an improvement until they neared the portals of their goal, their shadowy land of El Dorado. Gradually the sinuous curves on the horizon loomed up plainer to the view, and lo! as they crested an intervening sand hillock, a strange sight met their gaze. As far as the eye could reach west or north, a sea of undulating sand ridges appeared, rolling down like gigantic breakers from the dim north-west, the mighty valleys between each swelling sand-wave being over a hundred yards apart and fully thirty feet deep. Capping these wonderful billows regular rows of saltbush and spinifex, so regularly spread, indeed, that in the rosy morning light the whole scene was like some Brobdingnagian field, with furrows bearing luxurious vegetation. "I reckon we has struck the land o' Goschen at last," said the Shadow, joyously. "It does look pretty," Jack allowed hesitatingly, as they stood to take in the view, and waited for the others to come up. Indeed, so unaccustomed had they grown to seeing such close array of even the wiry desert growths that for the moment all imagined they looked upon a wildering forest. The saltbush was by the fantasy of
78.
mirage exalted tolordly proportions, and the spiky spinifex patches drooped in the sun's rays like the spreading fronds of the stately palm. Mackay dispelled the illusion; he of all the party seemed ill at ease. "I didna think the sand-waves extended so far back," he muttered, half to himself. Then he added, aloud, "It's no' a land o' promise you're lookin' at, boys; it's a deceiving land o' misery an' dispair, where many a good man has lost his life." "But what about the beautiful trees and shrubs?" asked Bob, in wonderment. "They seem to stretch back for miles and miles." "It's only another case where distance lends enchantment, as the poet says, my lad. Your trees are only saltbush, and instead o' growin' closely, there's over fifty yards between each o' them; it's those behind that fill in the gaps. The eye can never understand the perspective o' this country, the air is so clear that distant objects almost blend wi' what is close at hand." He spoke truly. When they forced their way at a difficult angle across the vast undulations, they discovered to their sorrow that only the sparsest of vegetation found root on the hill crests, while the long interstices were absolutely barren. Not only this, but the sand on the inclines and declivities was so loosely packed that the camels sank to the knees in their strenuous efforts to scale them, and had to be pulled over the barring obstacles by sheer force. "A day of this will just about finish Remorse," said Mackay, noting how that meek yet willing animal was labouring under its load. "I think, Bob, we'd better keep in the trough o' these confounded waves until we run oot o' them, I ken we must be near the edge as it is, for I mind that Fortunate Spring was a good day's travel past their eastern limit. That was why the chief called it by that name. We were vera nearly lost on those same ridges; we didna find a drop o' water for over a hundred miles, and we were just about dead beat when we came upon it."
79.
"How far dothey run towards the north?" questioned Bob. "Well, Carnegie, who was one o' the finest explorers that ever handled a sextant, calculated they covered nearly three hundred miles o' West Australia. What their area is God only knows, yet it must be over fifty thousand square miles." "I should think this would be nearly as bad as the Sahara," said Jack, as he tugged at Misery's rope. "I haven't seen a drop of water since we started, unless that which Bob fell into." "The Sahara?" echoed Mackay. "Why, we wouldn't ca' it a desert at all. It's only because it's so near the old country that it is considered to be anything extraordinary. This country, Jack, wouldna be an explorer's preserve if it contained as much water as the Sahara. It would be overrun in every direction by gold-miners." Then Jack was silent, marvelling greatly that in his earlier youth at school he had learned so little concerning the vast sandy wastes of Australia. Soon, as they kept on their altered course, the retarding undulations began to grow less and less high, and by late afternoon they had merged into the monotonous plains, now welcome indeed to the travellers after their encounter with the formidable sand- ridges. But their progress that day had barely totalled ten miles, and the camels were well-nigh exhausted after their extreme exertions. The poor brutes had had a severe experience from the beginning, and the rough usage was telling heavily upon their strength. That night they could scarcely muster up sufficient spirit to chew their usual meal of saltbush tips, and, after a few weak efforts, Remorse and Repentance lay down in the sand, while Misery and Fireworks gazed at the little group around the camp-fire with mute, appealing eyes. "I hope we don't have any trouble finding that spring," said Mackay, anxiously, and instinctively they all turned to Bob with a questioning look. The young navigator winced as he took out his notebook and hurriedly checked his previous calculations.
80.
"We were inlatitude 28° 24´ 7´´ at noon to-day," he said quietly; "that should make us about seven miles only from the location of Fortunate Spring, allowing we made five miles since lunch." "But the longitude, Bob?" asked Mackay. "How do we stand for that?" Bob again examined his log-book. "I have it marked at 125° 11´ 17 ´´," he answered, "but we came a good bit easterly since that. I'll try it again in the morning, though I think we're almost on the correct line now, and should hit the Spring by going due north." He handed the book to Mackay, who glanced at the figures and mentally checked the simpler calculations, but he did not ask for Bob's table of logarithms, and the young man felt satisfied. Bob, indeed, was sure of his positions; they had been worked out with painful exactitude, but he could not help feeling anxious about the morrow. The country in the vicinity seemed so utterly arid and barren. Could the original figures he received be correct? Might not possibly some mistake have crept into Bentley's estimates? He shuddered at the thought, then was immediately sorry for the passing doubt. Who was he who dared question the accuracy of an old and tried explorer's chart? Yet Bob went to sleep that night feeling vaguely uneasy, and by early sunrise he was up taking altitudes, Jack and the Shadow attending him to mark the time of his observations. It was nearly nine o'clock before they were ready to move out that morning; the camels had for a long time refused to be loaded, and when loaded they could not be prevailed upon to arise to their feet, until forced to do so by the necessarily cruel expedient of lighting fires under their noses. "That's nothing, Jack," Mackay said with a laugh, for he had noticed the look of pain on the boy's face. "They get up long before they're hurt; their hide is like leather, you know, and camels are vera often stubborn and annoying when there's really no occasion for it."
81.
But he knewwell that the poor animals were not refractory without reason on this morning, though he endeavoured to make light of the fact. Wearily the heavily laden beasts trudged along, and when the first hour passed, and the sand showed signs of hardening, the Shadow made a valiant effort to infuse life into their hulking movements by blowing at his long-unused mouth-organ vociferously, and making the air resound with discordant notes, for his cracked lips could ill glide along the reeds with any degree of certainty. Bob, who was striding along well in advance, smiled as he heard the concert thus let loose, and he smiled the more when the dismal voices of Emu Bill and Never Never Dave were added to the chorus; and, looking back, he observed these two worthies prancing on with martial steps, though certainly not with martial grace, for their bodies were bent as they pulled their reluctant charges onwards, and their feet, notwithstanding their jaunty uplifting, went down almost in the same place. And Mackay, looking back at the perspiring musician, nodded encouragingly, much to that alert youth's amazement, for he had expected but a rude check as a reward for his labours. Not only did he thus ostensibly appreciate the lively music, but he joined in with his comrades lustily in their vocal exercises; and in this way the labouring train progressed, and almost unnoticeably a thin, straggling array of mallee and mulga shrubs began to dot the hardening sand surface, a slight dip in the land had obscured them from earlier view. By eleven o'clock the sand had merged into the longed-for iron-pebble strewn plains, and now the scrub was comparatively abundant all around, and the tough, wiry grasses which the camels loved appeared in greater profusion. Yet no signs of Fortunate Spring. "It can't be far off now," said Bob, hopefully. "I'd better fix our position again before we go further, in case we might pass it." "And that would be easily done, my lad," spoke Mackay. "I remember well that the water was in a mallee flat, just scrubby country like this, but there was no kind o' landmark except a fair-
82.
sized lime treewhich grew beside it, an' I canna see any lime trees about here." "I'll have another shot at the sun," decided Bob, and at once the team came to a halt, while Jack hastily unstrapped the sextant and chronometer from Misery's back. A few minutes more and Bob had worked out the necessary calculation. "I make the latitude come out exactly," he said gravely. "Try again, Bob; try again," urged Mackay. With sinking heart Bob once more levelled his sextant; the horizon was easily discernible through the scraggy bush, and the flat itself was level as could be. "I find the latitude reading correct," he repeated, with bloodless lips; "and the longitude," he added, after a pause, "is the same as it was this morning, the same as is marked on my chart over the location of the Spring." "We'll soon find it, if it is near abouts," cried Emu Bill, cheerily. "Don't fret, Bob, them springs have a habit of getting lost at times. Come on, Never Never, come an' help me to smell it out wi' that tender nose o' yours." And they rushed off into the bush towards the west. The Shadow and Jack started to follow, but Mackay recalled them. "You two had better look around due north," he said, "and I'll tackle the east myself. Now don't go further than a mile, an' signal wi' a revolver-shot if ye find anything." Without a word they departed on their quest, and Mackay and Bob were left alone. Calmly the elder man interrogated the lad, who was standing in an attitude of deepest dejection, the sextant hanging loosely in his hand.
83.
"And is thereno room for a mistake in any o' your figures, Bob?" "None, none, that I can imagine. I have been particularly careful ——" Bob could not finish his sentence, a flood of emotion swept over him, and he sat down in the sand and covered his face with his hands. "Why, my laddie, ye mustn't blame yoursel' for no error o' yours," spoke Mackay, kindly, gazing at the despondent youth with a strange light in his keen grey eyes. "Brace yoursel' up, Bob; we'll likely find the spring at no great distance, an' if we don't, well—we'll look for another one if the camels stand by us." He hurried away into the eastward scrub. Bob arose and gazed after him with quivering eyelids. "Yes," he murmured brokenly, "I have brought you all to your death, and I can do nothing now to save.... I know the error is not mine, but I cannot and will not blame a dead man.... I wonder what can possibly be wrong." He shook his head in utter hopelessness, then he glanced at the sextant, lying as he had left it, half buried in the sand. He took it up and brushed the silvered arc carefully with the ragged sleeve of his shirt, and was preparing to place it in its case when a new idea seemed to strike him. He grasped the instrument with a firmer grip and stood erect, a new light, a light of gladness shining in his eyes. "It's strange I never thought of it before," he said aloud; "a minute or two either way would make all the difference." He picked up the chronometer, which lay idly at his feet, and examined it critically. "It's just possible," he muttered, "the jolting of the camel may have made it go a bit fast; I wonder if I can check it. I am going to try." Long and eagerly he gazed at the sun through the powerful telescope of the sextant, and every now and then he would note down his observations, and consult the Nautical Almanac which lay
84.
open before him.In the midst of these proceedings, Emu Bill and Never Never Dave returned, after a fruitless search, and while they stood watching him, Jack and the Shadow also made their appearance, and lined up beside the other two in solemn silence. There was no need to ask them if they had been successful, their faces plainly indicated disappointment, though they both strove hard to hide their feelings. As for the first arrivals, their rugged countenances betrayed not the slightest trace of emotion. Bill calmly chewed a quid of tobacco, and Dave reflectively pulled at his pipe. To them it did not seem to be a matter of much moment whether they found the spring or not. At length Bob threw down the sextant with a weary sigh. "The chronometer is right," said he, sadly; then, as his comrades looked at him questioningly, he faltered: "I've done my best, boys ... the fault may not be altogether mine, but ... I am responsible to you.... What can you think of me——?" He gave way completely. Then out spoke Emu Bill, and his voice rang firm and true— "Shoot me fur a dingo if I'll listen to you miscallin' yourself, Bob. You has shown us afore what ye were made o', an' hang me for a cross- eyed Chinese if I'll believe you've made the mistake." "I'm right with ye thar, Bill," grunted Never Never. Bob looked at them in silent gratitude that was more potent than words. "Blow me!" blurted out the Shadow, "this ain't no funeral circus." He strode aside and examined the canvas bags overlapping Remorse's tough hide; they were flat and empty, the last drop had gone. He rejoined the little circle quietly, and held out his hand to Bob, who was gazing with unseeing eyes into the horizon. "I knows it ain't your fault," he said simply. Jack alone had not spoken, but Bob knew his comrade's thoughts; he knew the loyal courage and devotion of the boy's heart.
85.
And all thistime Mackay had not come back, nor had any welcome signal been heard. Bob commenced to fear that he would not come back unless he had something to report. "What did ye mean by sayin' the chronometer was right, Bob?" asked Emu Bill, suddenly. "If it had gone fast or slow, my longitude, which I calculated by it, would have been out accordingly," replied Bob, listlessly. "I thought the jolting might have affected it." "Why then," returned Bill, "ain't it more likely that Bentley's time was wrong? If he came in from the west across the whole darned stretch o' sand-ridges, I reckon he would bust things up a bit." Bob was startled into fresh energy. "Of course, you're right, Bill!" he cried excitedly. "I've been so anxiously looking for a possible error in my own instrument, I never thought of it occurring with Bentley's. I believe you've hit the solution of the whole difficulty. We'll find Fortunate Spring due east of us in that case, for his latitude would be sure to be right." "We'll get under way at oncet then," grunted Never Never Dave. "We're bound to meet Mackay comin' back." At once Jack rushed to Misery's head, and the others hastened to their posts. Bob picked up the sextant and chronometer, and with a surging hope in his heart led the way in the direction that Mackay had taken. Slowly, slowly, they broke through the scrub, Misery's bell sending out its melancholy note, and shattering the oppressive stillness which had prevailed but a few minutes before. Onward they went and onward, and yet no sign of Mackay, and no sign of a spring to gladden their weary eyes. About two miles had been traversed, and the spirits of the forlorn party were drooping fast, when from the bush but a few hundred yards ahead a revolver shot boomed out loudly. With one accord the camels stopped dead. They seemed to realize that something was about to happen. Again came
86.
Welcome to ourwebsite – the perfect destination for book lovers and knowledge seekers. We believe that every book holds a new world, offering opportunities for learning, discovery, and personal growth. That’s why we are dedicated to bringing you a diverse collection of books, ranging from classic literature and specialized publications to self-development guides and children's books. More than just a book-buying platform, we strive to be a bridge connecting you with timeless cultural and intellectual values. With an elegant, user-friendly interface and a smart search system, you can quickly find the books that best suit your interests. Additionally, our special promotions and home delivery services help you save time and fully enjoy the joy of reading. Join us on a journey of knowledge exploration, passion nurturing, and personal growth every day! ebookmasss.com