You are on page 1of 51

Functional Programming in R 4 -

Second Edition Thomas Mailund


Visit to download the full and correct content document:
https://ebookmass.com/product/functional-programming-in-r-4-second-edition-thomas
-mailund/
Thomas Mailund

Functional Programming in R 4
Advanced Statistical Programming for Data Science,
Analysis, and Finance
2nd ed.
Thomas Mailund
Aarhus N, Denmark

ISBN 978-1-4842-9486-4 e-ISBN 978-1-4842-9487-1


https://doi.org/10.1007/978-1-4842-9487-1

© Thomas Mailund 2017, 2023

Apress Standard

The use of general descriptive names, registered names, trademarks,


service marks, etc. in this publication does not imply, even in the
absence of a specific statement, that such names are exempt from the
relevant protective laws and regulations and therefore free for general
use.

The publisher, the authors and the editors are safe to assume that the
advice and information in this book are believed to be true and accurate
at the date of publication. Neither the publisher nor the authors or the
editors give a warranty, express or implied, with respect to the material
contained herein or for any errors or omissions that may have been
made. The publisher remains neutral with regard to jurisdictional
claims in published maps and institutional affiliations.

This Apress imprint is published by the registered company APress


Media, LLC, part of Springer Nature.
The registered company address is: 1 New York Plaza, New York, NY
10004, U.S.A.
Any source code or 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.
Acknowledgments
I would like to 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.
Table of Contents
Chapter 1:​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
Currying
A Parameter Binding Function
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
About the Author
Thomas Mailund
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.
About the Technical Reviewer
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.
© The Author(s), under exclusive license to APress Media, LLC, part of Springer
Nature 2023
T. Mailund, Functional Programming in R 4
https://doi.org/10.1007/978-1-4842-9487-1_1

1. Introduction
Thomas Mailund1
(1) Aarhus N, Denmark

Welcome to Functional Programming in R 4. I wrote this book to have


teaching material beyond the typical introductory level most textbooks
on R have, where functions are simple constructions for wrapping up
some reusable instructions that you can then call when you need those
instructions run. In languages such as R, functions are more than this.
They are objects in their own right that you can also treat as data,
create and manipulate and pass around like other objects, and learning
how to do this will make you a far more effective R programmer.
The R language is a multiparadigm language with elements from
procedural programming, object-oriented programming, and functional
programming. Procedural programming focuses on the instructions you
want the computer to execute—add these numbers, put the result in
this variable, loop through this list, etc. Object-oriented programming,
on the other hand, focuses on what kind of data you manipulate, which
operations you can perform on them, and how they change when you
manipulate them. If you are interested in these aspects of the R
language, I have written another book, Advanced Object-Oriented
Programming in R, also by Apress, that you might be interested in.
Functional programming is the third style of programming, where
the focus is on transformations. Functions transform data from input to
output, and by composing transformations, you construct programs
from simpler functions to more involved pipelines for your data. In
functional programming, functions themselves are considered data, and
just as with other 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.
© The Author(s), under exclusive license to APress Media, LLC, part of Springer
Nature 2023
T. Mailund, Functional Programming in R 4
https://doi.org/10.1007/978-1-4842-9487-1_2

2. Functions in R
Thomas Mailund1
(1) Aarhus N, Denmark

In this chapter, we cover how to write functions in R. If you already


know much of what is covered, feel free to skip ahead. We will discuss
the way parameters are passed to functions as “promises,” a way of
passing parameters known as lazy evaluation. If you are not familiar
with that but know how to write functions, you can jump forward to
that section. We will also cover how to write infix operators and
replacement functions, so if you do not know what those are, and how
to write them, you can skip ahead to those sections. If you are new to R
functions, continue reading from here.

Writing Functions in R
You create an R function using the function keyword or, since R 4.1,
the \() syntax. For example, we can write a function that squares
numbers like this:

square <- function(x) x**2

or like this:

square <- \(x) x**2

and then use it like this:


square(1:5)

## [1] 1 4 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.
Variables you assign to 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
parentheses make R remove 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
Even parentheses and subscripting 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...
}
If x is negative, 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)


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
}
Then, if we call 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
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
## [1] 4
In the 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
need it), thus the 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)
you will get an 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
(evaluated using the global 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.
When we call f 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.
If we call the 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:
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)
for (i in 1: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.
The syntax for defining 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
Another random document with
no related content on Scribd:
The affinities with the order Stolonifera are clearly seen in the genera
Xenia and Telesto. Some species of Xenia form flattened or domed
colonies attached to stones or corals, with non-retractile anthocodiae
and body-walls united for only a short distance at the base. Young
Xenia colonies are in fact Stolonifera in all essential characters. In
Telesto prolifera we find a network of stolons encrusting coral
branches and other objects after the manner of the stolons of many
species of Clavularia, although the zooids do not arise from these
stolons singly, but in groups, with their body-walls fused together for
a certain distance. In Telesto rubra the spicules of the body-walls are
fused together to form a series of perforated tubes very similar in
some respects to the tubes of Tubipora.

A remarkable genus is Coelogorgia. Here we find a branching colony


arising from a basal stolon, and the axis of the main stem and of
each branch consists of a single very much elongated zooid bearing
on its thickened walls the branches of the next series and other
zooids. It is true that in this genus there is very little fusion of
neighbouring zooids, and the amount of true coenenchym is so small
that it can hardly be said to exist at all. Bourne[373] has united this
genus with Telesto into a family Asiphonacea, which he joins with the
Pennatulida in the order Stelechotokea; but their affinities seem to
be closer with the Alcyonacea than with the Pennatulacea, from
which they differ in many important characters.
Fig. 154.—Alcyonium digitatum, a single-lobed specimen, with some of the
zooids expanded.

The genus Alcyonium not only contains the commonest British


Alcyonarian (A. digitatum), but it is one of the most widely distributed
genera of all Alcyonaria that occur in shallow water.

The genera Sarcophytum and Lobophytum occur in shallow water in


the tropics of the old world. The former frequently consists of huge
toad-stool shaped masses, soft and spongy in consistency, of a
green, brown, or yellow colour. On some reefs the colonies of
Sarcophytum form a very conspicuous feature, and from their very
slimy, slippery surface, add to the minor dangers of wading in these
regions. Both genera are dimorphic. Some species of the genus
Sclerophytum,[374] which occur in the Indian Ocean, are so hard and
brittle that they might readily be mistaken for a Zoantharian coral.
This character is due to the enormous number of tightly packed
spicules borne by the coenenchym. Some of these spicules in S.
querciforme are 7 mm. × 1.7 mm.; the largest, though not the longest
(vide p. 335) of any spicules occurring in the order.

Another very important genus occurring on coral reefs, and of very


wide distribution, is Spongodes. This genus forms bushy and rather
brittle colonies of an endless variety of beautiful shapes and colours.
Arising from the neck of each anthocodia there are one or two long,
sharp, projecting spicules, which give the surface a very spiny or
prickly character.

The genera Siphonogorgia and Chironephthya form large brittle,


branching colonies which might readily be mistaken for Gorgonians.
The strength of the branches, however, is mainly due to the large,
densely packed, spindle-shaped spicules at the surface of the
coenenchym, the long coelenteric cavities of the zooids penetrating
the axis of both stem and branches. Siphonogorgia is usually
uniformly red or yellow in colour. Chironephthya, on the other hand,
exhibits a great variety of colour in specimens from the same reef,
and indeed in different branches of the same colony.

Fam. 1. Xeniidae.—Alcyonacea with non-retractile zooids. Spicules


very small discs, usually containing a relatively small proportion of
lime.

Xenia, Savigny; Indian Ocean and Torres Straits. Heteroxenia,


Kölliker; Red Sea, Cape of Good Hope, and Torres Straits.

Fam. 2. Telestidae.—Colonies arising from an encrusting


membranous or branching stolon. The erect stem and branches are
formed by the body-walls of two or three zooids only, from which
secondary zooids and branches of the next order arise.

Telesto, Lamouroux, widely distributed in warm waters of the


Atlantic, Pacific, and Indian Oceans. The genus Fascicularia, Viguier,
from the coast of Algiers, seems to be related to Telesto, but the
groups of zooids are short, and do not give rise to branches.

Fam. 3. Coelogorgiidae.—The colony arborescent, attached by


stolon-like processes. The stem formed by an axial zooid with
thickened body-walls. Branches formed by axial zooids of the
second order, and branchlets by axial zooids of the third order, borne
either on two sides or in spirals by the main stem. Genus
Coelogorgia, Zanzibar.

Fam. 4. Alcyoniidae.—The colonies of this family are usually soft


and fleshy, and the spicules, evenly distributed throughout the
coenenchym, do not usually fuse or interlock to form a continuous
solid skeleton. They may be unbranched or lobed, never dendritic in
form. The principal genera are:—Alcyonium, Linnaeus,
cosmopolitan, but principally distributed in temperate and cold
waters. Alcyonium digitatum is the commonest British Alcyonarian. It
is found in shallow water, from the pools left at low spring tides to
depths of 40 or 50 fathoms, at most places on the British shores. It is
stated by Koehler to descend into depths of over 300 fathoms in the
Bay of Biscay. There are two principal varieties; one is white or pale
pink in the living condition, and the other yellow. In some localities
the two varieties may be found in the same pools. Another species,
Alcyonium glomeratum, placed in a distinct genus (Rhodophyton) by
Gray, and distinguished from the common species by its red colour
and long digitate lobes, is found only off the coast of Cornwall.
Paralcyonium, Milne Edwards; Mediterranean. Sclerophytum, Pratt;
sometimes dimorphic, Indian Ocean. Sarcophytum, Lesson;
dimorphic, principally tropical. Lolophytum, Marenzeller; dimorphic,
tropical. Anthomastus, Verrill; dimorphic, Atlantic Ocean, deep water.
Acrophytum, Hickson; dimorphic, Cape of Good Hope.

Fam. 5. Nephthyidae.—Colonies dendritic. Usually soft and flexible


in consistency. Nephthya, Savigny; Indian and Pacific Oceans.
Spongodes, Lesson; widely distributed in the Indian and Pacific
Oceans.

Fam. 6. Siphonogorgiidae.—Colonies often of considerable size.


Dendritic. Spicules usually large and abundant, giving a stiff, brittle
consistency to the stem and branches. Siphonogorgia, Kölliker; Red
Sea, Indian, and Pacific tropics. Chironephthya, Wright and Studer;
Indian and Pacific Oceans. Lemnalia, Gray; Zanzibar. Agaricoides,
Simpson;[375] Indian Ocean, 400 fathoms.

Order IV. Gorgonacea.


This order contains a very large number of dendritic and usually
flexible corals occurring in nearly all seas and extending from
shallow waters to the very great depths of the ocean. A large
proportion of them are brightly coloured, and as the principal
pigments are fixed in the spicules, and are therefore preserved when
the corals are dead and dried, they afford some of the most
attractive and graceful objects of a natural history museum.
The only character that separates them from the Alcyonacea is that
they possess a skeletal axis that is not perforated by the coelenteric
cavities of the zooids. The coelenteric cavities are usually short. The
order may conveniently be divided into two sub-orders.

Sub-Order 1. Pseudaxonia.
The axis in this sub-order consists of numerous spicules tightly
packed together, or cemented together by a substance which is
probably allied to horn in its chemical composition. This substance
may be considerable in amount, in which case it remains after
decalcification as a spongy, porous residue; or it may be so small in
amount, as in Corallium, that the axis appears to be composed of
solid carbonate of lime. The statement is usually made that the axis
is penetrated by nutritive canals in certain genera, but the evidence
upon which this is based is unsatisfactory and in some cases
unfounded. There can be no doubt, however, that in some genera
the axis is porous and in others it is not, and this forms a useful
character for the separation of genera.

Fam. 1. Briareidae.—The medullary substance consists of closely


packed but separate spicules embedded in a soft horny matrix,
which is uniform in character throughout its course. Nearly all the
genera form dendritic colonies of considerable size.

The principal genera are:—Solenocaulon, Gray; Indian Ocean and


North Australia. Many of the specimens of this genus have fistulose
stems and branches. The tubular character of the stem and
branches is probably caused by the activity of a Crustacean,
Alpheus, and may be regarded as of the nature of a gall-formation.
[376] Paragorgia, M. Edwards; Norwegian fjords, in deep water. This
genus forms very large tree-like colonies of a ruby-red or white
colour. It is perhaps the largest of the dendritic Alcyonarians. It is
dimorphic. Spongioderma, Kölliker; Cape of Good Hope. The surface
of this form is always covered by an encrusting sponge. Iciligorgia,
Ridley; Torres Straits. The stem and branches are compressed and
irregular in section.

Fam. 2. Sclerogorgiidae.—The medullary mass forms a distinct


axis consisting of closely packed elongate spicules with dense horny
sheaths.

Suberogorgia, Gray, has a wide distribution in the Pacific Ocean,


Indian Ocean, and the West Indies. Keroeides, W. and S., comes
from Japan.

Fam. 3. Melitodidae.—The axis in this family exhibits a series of


nodes and internodes (Fig. 155), the former consisting of pads
formed of a horny substance with embedded spicules, the latter of a
calcareous substance with only traces of a horny matrix. The
internodes are quite rigid, the nodes however give a certain degree
of flexibility to the colony as a whole. Neither the nodes nor the
internodes are penetrated by nutritive canals, but when dried the
nodes are porous.
Fig. 155.—Melitodes dichotoma, showing the swollen nodes and the internodes.

The principal genera are:—Melitodes, Verrill; widely distributed in the


Indian and Pacific Oceans, Cape of Good Hope, etc. This genus is in
some localities extremely abundant and exhibits great brilliancy and
variety of colour. The branching is usually dichotomous at the nodes.
Wrightella, Gray. This is a delicate dwarf form from Mauritius and the
coast of South Africa. Parisis, Verrill; Pacific Ocean from Formosa to
Australia but not very common. One species from Mauritius. The
branches arise from the internodes.

Fam. 4. Coralliidae.—The axis is formed by the fusion of spicules


into a dense, solid, inflexible, calcareous core.

Corallium, Lamarck. Corallium nobile, Pallas, the "precious coral,"


occurs in the Mediterranean, chiefly off the coast of North Africa, but
also on the coasts of Italy, Corsica, Sardinia, and it extends to the
Cape Verde Islands in the Atlantic Ocean. C. japonicum, Kishinouye,
called Akasango by the fishermen, occurs off the coast of Japan,
and C. reginae, Hickson, has recently been described from deep
water off the coast of Timor.[377] The genus Pleurocorallium, Gray, is
regarded by some authors as distinct, but the characters that are
supposed to distinguish it, namely, the presence of peculiar "opera-
glass-shaped spicules," and the occurrence of the verrucae on one
side of the branches only, are not very satisfactory. The following
species are therefore placed by Kishinouye[378] in the genus
Corallium:—C. elatius, Ridley (Momoirosango); C. konojoi,
Kishinouye (Shirosango); C. boshuensis, K.; C. sulcatum, K.; C.
inutile, K.; and C. pusillum, K.,—all from the coast of Japan. Of the
coral obtained from these species, the best kinds of Momoirosango
vary in price from £30 per pound downwards according to the quality.
The Shirosango is the least valuable of the kinds that are brought
into the market, and is rarely exported.[379] Three species of
Corallium (Pleurocorallium) have been described from Madeira,[380]
and one of these, C. johnsoni, has recently been found in 388
fathoms off the coast of Ireland.[381] Other species are C.
stylasteroides, from Mauritius; C. confusum, Moroff,[382] from
Sagami Bay in Japan; and an undescribed species obtained by the
"Siboga," off Djilolo. These corals range from shallow water to
depths of 300-500 fathoms. Pleurocoralloides, Moroff, differs from
the others in having very prominent verrucae and in the character of
the large spindle-shaped and scale-like spicules. It was found in
Sagami Bay, Japan. Specimens attributed to the genus
Pleurocorallium have been found fossil in the white chalk of France,
but Corallium has been found only in the tertiaries.[383]

Sub-Order 2. Axifera.
The axis in this sub-order may be horny, or horny with a core of
calcium carbonate, or composed of horn impregnated with calcium
carbonate, or of nodes of horn alternating with internodes of calcium
carbonate. It may be distinguished from the axis of the Pseudaxonia
by the fact that in no case have definite spicules been observed to
take part in its formation. It has been suggested that as the Axifera
represent a line of descent distinct from that of the Pseudaxonia they
should be placed in a separate order. Apart from the character of the
axis, however, the two sub-orders show so many affinities in their
general anatomy that it is better to regard the two lines of descent as
united within the Gorgonacean limit. It is very improbable that the
two groups sprang independently from a stoloniferous ancestor.
Fam. 1. Isidae.—This family includes all those Axifera in which the
axis is composed of alternate nodes of horn and internodes of
calcareous substance.

There can be little doubt of the close affinities of many of the genera
of this family with the Melitodidae among the Pseudaxonia. In both
the coenenchym is thin and the coelenteric cavities short. No
important differences have been observed between the structure of
the zooids of the two families, and now that we know that the
"nutritive canals" of Melitodes do not perforate the nodes there is no
important difference left between the coenosarcal canal systems.
The structure and method of calcification of the internodes of the two
families are very similar. The main difference between them is that
the nodes of the Isidae are purely horny, whereas in the Melitodidae
the horny substance of the nodes contains calcareous spicules.

The principal genera are:—Isis, Linnaeus; Pacific Ocean. This genus


forms substantial fan-shaped colonies with, relatively, a thick
coenenchym, short stout internodes and black horny nodes.
Mopsea, Lamouroux; Coast of Australia. The verrucae are club-
shaped and are arranged in spiral rows round the stem. Acanella,
Gray; principally found in deep water in the Atlantic Ocean but also
in the Pacific. The internodes are long and the branches arise from
the nodes. Most of the species occur in deep water, some in very
deep water (A. simplex, 1600 to 1700 fathoms). In this and the
following genera the coenenchym is thin and the zooids imperfectly
or not retractile. Ceratoisis, Wright; Atlantic Ocean, extending from
shallow to deep water. The branches arise from the nodes.
Chelidonisis, Studer; deep water off the Azores. Isidella, Gray;
Mediterranean Sea. Bathygorgia, Wright; off Yokohama, 2300
fathoms. This genus is unbranched, with very long internodes and
short nodes. The zooids are arranged on one side only of the stem.

Fam. 2. Primnoidae.—This is a well-marked family. The axis of the


colonies is horny and calcareous. The coenenchym and the non-
retractile zooids are protected by scale-like spicules, which usually
overlap and form a complete armour for the protection of the soft
parts. On the aboral side of the base of each tentacle there is a
specialised scale, and these fit together, when the tentacles are
folded over the peristome, to form an operculum.

The principal genera are:—Primnoa, Lamouroux; Atlantic Ocean,


occurring also in the Norwegian fjords. This genus is usually found in
moderately deep water, 100 to 500 fathoms. Primnoella, Gray. This
genus seems to be confined to the temperate seas of the southern
hemisphere. It is unbranched. The zooids are arranged in whorls
round the long whip-like stem. Plumarella, Gray; southern
hemisphere, in moderately deep water. This is branched pinnately in
one plane. The zooids are small and arise at considerable intervals
alternately on the sides of the branches. Stenella, Gray; widely
distributed in deep water. The zooids are large and are arranged in
whorls of three situated at considerable distances apart. Stachyodes,
W. and S.; Fiji, Kermadecs, Azores, in deep water. Colony feebly
branched. Zooids in regular whorls of five. Other genera belonging to
this group of Primnoidae are Thouarella, Gray, and Amphilaphis,
Antarctic seas.

The following genera are placed in separate sub-families:—


Callozostron, Wright; Antarctic Sea, 1670 fathoms. The axis is
procumbent and the zooids are thickly set in rows on its upper
surface. The zooids are protected by large imbricate scales, of which
those of the last row are continued into long spine-like processes.
Calyptrophora, Gray; Pacific Ocean, in deep water. The base of the
zooids is protected by two remarkably large scales. Primnoides, W.
and S.; Southern Ocean. The opercular scales are not distinctly
differentiated and the calyx is therefore imperfectly protected.

Fam. 3. Chrysogorgiidae.[384]—The axis in this family is composed


of a horny fibrous substance with interstratified calcareous particles,
and it springs from a calcareous plate, which sometimes gives off
root-like processes. It may be unbranched or branched in such a
way that the branches of the second, third, and subsequent orders
assume in turn the direction of the base of the main axis. The axis is
frequently of a metallic iridescent appearance. The zooids usually
arise in a single straight or spiral row on the branches, and are not
retractile. The coenenchym is thin. The spicules vary considerably,
but in a very large proportion of the species they are thin, oval, or
hour-glass plates (Fig. 149, 10, p. 336).

By some authors this family is considered to be the simplest and


most primitive of the Axifera; but the delicate character of the axis of
the main stem and branches, the thinness of the coenenchym, the
position of the zooids on one side of the branches only, and the
tenuity of the calcareous spicules may be all accounted not as
primitive characters, but as special adaptations to the life in the slow
uniform currents of deep water.

The principal genera are:—Lepidogorgia, Verrill; Atlantic and Pacific


Oceans, 300 to 1600 fathoms. Axis unbranched. Zooids large and
arranged in a single row. Trichogorgia, Hickson; Cape of Good Hope,
56 fathoms. Colony branching in one plane. Zooids numerous and
on all sides of the branches. Chrysogorgia, D. and M.; deep water.
Axis branched. Spicules on the zooids always large. Metallogorgia,
Versluys; Atlantic Ocean, 400 to 900 fathoms. Basal part of the stem
unbranched (monopodial). Iridogorgia, Verrill. Spiral stem and
branches. Pleurogorgia, Versluys. Axis branched in one plane.
Coenenchym thick. Riisea, D. and M. Monopodial stem and thick
coenenchym.

Fam. 4. Muriceidae.—This is a large family, exhibiting very great


variety of habit. The spicules are often very spiny, and project
beyond the surface of the ectoderm, giving the colony a rough
appearance. A great number of genera have been described, but
none of them are very well known. The family requires careful
revision.

The more important genera are:—Acanthogorgia, Gray; principally in


deep water in the Atlantic Ocean. The calices are large, cylindrical,
and spiny. Villogorgia, D. and M.; widely distributed. Delicate,
graceful forms, with thin coenenchym. Echinomuricea, Verrill;
Muricea, Lamouroux; Paramuricea, Köll; Acamptogorgia, W. and S.;
Bebryce, Philippi.

Fam. 5. Plexauridae.—In this family we find some of the largest and


most substantial Gorgonids. The axis is usually black, but its horny
substance may be impregnated with lime, particularly at the base.
The coenenchym is thick, and the zooids are usually completely
retractile, and the surface smooth. The species of the family are
principally found in shallow water in warm or tropical regions.

The principal genera are:—Eunicea, Lamouroux. The calices are


prominent, and not retractile. Plexaura, Lamouroux; Euplexaura,
Verrill. Eunicella, Verrill. With an outer layer of peculiar torch-shaped
spicules. The only British species of this order is Eunicella cavolini
(formerly called Gorgonia verrucosa). It is found in depths of 10 to 20
fathoms off the coast of the English Channel and west of Scotland.
Occasionally specimens are found in which a gall-like malformation
with a circular aperture is seen, containing a Barnacle. Such gall
formations, common enough in some species of Madreporaria, are
rarely found in Alcyonaria.

Fig. 156.—Eunicella cavolini. Some branches of a large dried specimen, showing


a gall formed by a Cirripede.

Fam. 6. Gorgoniidae.—This family contains some of the


commonest and best-known genera of the order. They usually form
large flexible branched colonies with delicate horny axes and thin
coenenchym. The zooids are usually completely retractile.

The principal genera are:—Gorgonia, Linn. This genus includes


Gorgonia (Rhipidogorgia) flabellum, the well-known fan Gorgonia
with intimately anastomosing branches, from the warm waters of the
Atlantic Ocean. The genera Eugorgia, Verrill, and Leptogorgia, Milne
Edwards, differ from Gorgonia in the character of the spicules. In
Xiphigorgia, Milne Edwards, from the West Indies, the branches are
much compressed, forming at the edges wing-like ridges, which bear
the zoopores in rows. Malacogorgia, Hickson, has no spicules. Cape
of Good Hope.

Fam. 7. Gorgonellidae.—In this family the horny axis is


impregnated with lime. The surface of the coenenchym is usually
smooth, and the spicules small. The colonies are sometimes
unbranched (Juncella). In the branching forms the axis of the
terminal branches is often very fine and thread-like in dimensions.

Fig. 157.—Verrucella guadaloupensis, with an epizoic Brittle star (Oph.) of similar


colour.

The principal genera are:—Gorgonella, with a ramified flabelliform


axis; Ctenocella, with a peculiar double-comb manner of branching;
and Juncella, which forms very long unbranched or slightly branched
colonies, with club-shaped spicules. All these genera are found in
shallow water in the tropical or semi-tropical regions of the world.
Verrucella is a genus with delicate anastomosing branches found
principally in the shallow tropical waters of the Atlantic shores. Like
many of the Gorgonacea, with branches disposed in one plane
(flabelliform) Verrucella frequently carries a considerable number of
epizoic Brittle stars, which wind their flexible arms round the
branches, and thus obtain a firm attachment to their host. There is
no reason to suppose that these Brittle stars are in any sense
parasitic, as a specimen that bears many such forms shows no sign
of injury or degeneration, and it is possible they may even be of
service to the Verrucella by preying upon other organisms that might
be injurious. An interesting feature of the association is that the
Brittle stars are of the same colour as the host, and the knob-like
plates on their aboral surface have a close resemblance to the
verrucae (Fig. 157).

Order V. Pennatulacea.
The Sea-pens form a very distinct order of the Alcyonaria. They are
the only Alcyonarians that are not strictly sedentary in habit, that are
capable of independent movement as a whole, and exhibit a bilateral
symmetry of the colony. No genera have yet been discovered that
can be regarded as connecting links between the Pennatulacea and
the other orders of the Alcyonaria. Their position, therefore, is an
isolated one, and their relationships obscure.

The peculiarities of the order are due to the great growth and
modification in structure of the first formed zooid of the colony. This
zooid (Oozooid, Hauptpolyp, or Axial zooid) increases greatly in
length, develops very thick fleshy walls, usually loses its tentacles,
digestive organs, and frequently its mouth, exhibits profound
modification of its system of mesenteries, and in other ways
becomes adapted to its function of supporting the whole colony.
Fig. 158.—Diagram of a Sea-pen. L, leaves composed of a row of autozooids; R,
rachis; St, stalk; T, anthocodia of the axial zooid, usually suppressed. (After
Jungersen.)

The axial zooid shows from an early stage of development a division


into two regions: a distal region which produces by gemmation on
the body-wall numerous secondary zooids, and becomes the rachis
of the colony; and a proximal region which becomes the stalk or
peduncle, and does not produce buds (Fig. 158). The secondary
zooids are of two kinds: the autozooids and the siphonozooids. The
former have the ordinary characters of an Alcyonarian zooid, and
produce sexual cells; the latter have no tentacles, a reduced
mesenteric system, and a stomodaeum provided with a very wide
siphonoglyph.

The arrangement of the autozooids and siphonozooids upon the


axial zooid is subject to great modifications, and affords the principal
character for the classification of the order. In the Pennatuleae the
autozooids are arranged in two bilaterally disposed rows on the
rachis, forming the leaves or pinnae of the colony (Fig. 158). The
number in each leaf increases during the growth of the colony by the
addition of new zooids in regular succession from the dorsal to the
ventral side of the rachis[385] (Fig. 159). In other Pennatulacea the
autozooids are arranged in rows which do not unite to form leaves
(Funiculina), in a tuft at the extremity of a long peduncle (Umbellula),
scattered on the dorsal side of the rachis (Renilla, Fig. 160), or
scattered on all sides of the rachis (Cavernularia, Fig. 161). In those
forms in which the autozooids are scattered the bilateral symmetry of
the colony as a whole becomes obscured. The siphonozooids may
be found on the leaves (Pteroeides), but more frequently between
the leaves or rows of autozooids, or scattered irregularly among the
autozooids. Usually the siphonozooids are of one kind only, but in
Pennatula murrayi there is one specially modified siphonozooid at
the base of each leaf,[386] which appears to have some special but
unknown function.

Fig. 159.—Diagram of a portion of a rachis of a Sea-pen, aut, The rows of


autozooids; 1-6, the order of age of the autozooids composing a leaf; D, the
dorsal side of the rachis; Si, the siphonozooids; V, the ventral side of the
rachis. (After Jungersen.)

In Umbellula gracilis each siphonozooid bears a single pinnate


tentacle, and in some other species of the same genus there is a
tentacle which is not pinnate.[387]

The zooids and coenenchym are usually protected by a crust of


coloured or colourless, long, smooth, needle-like, calcareous
spicules, situated principally in the superficial layer, so as to leave
the subjacent tissues soft and spongy in texture. In some cases the
spicules are smooth double clubs, rods, discs, or irregular granules,
and in Sarcophyllum, Chunella, some species of Umbellula and
others, there is no calcareous skeleton. The tuberculated spindles,
so common in other Alcyonaria, are not found in any species. In
most genera a horny, or calcified horny rod is embedded in the
central part of the axial polyp, serving as a backbone or support for
its muscles. It is absent, however, in Renilla, and reduced or absent
in Cavernularia.
The sexual organs are borne by the mesenteries of the autozooids
only, and each colony is either male or female. There is no record of
hermaphroditism in the order. The eggs contain a considerable
amount of yolk, and fertilisation is effected in the sea-water after their
discharge. The segmentation is irregular, and the free-swimming
ciliated larva (of Renilla) shows the rudiments of the first buds from
the axial polyp before it settles down in the mud.

The Sea-pens are usually found on muddy or sandy sea-bottoms,


from a depth of a few fathoms to the greatest depths of the ocean. It
is generally assumed that their normal position is one with the
peduncle embedded in the mud and the rachis erect. Positive
evidence of this was given by Rumphius, writing in 1741, in the case
of Virgularia rumphii and V. juncea at Amboina,[388] and by Darwin in
the case of Stylatula darwinii at Bahia Blanca.[389]

"At low water," writes Darwin, "hundreds of these zoophytes might be


seen projecting like stubble, with the truncate end upwards, a few
inches above the surface of the muddy sand. When touched or
pulled they suddenly drew themselves in with force so as nearly or
quite to disappear."

It is not known whether the Pennatulids have the power of moving


from place to place when the local conditions become unfavourable.
It is quite probable that they have this power, but the accounts given
of the Sea-pens lying flat on the sand do not appear to be founded
on direct observation. The fable of Pennatula swimming freely "with
all its delicate transparent polypi expanded, and emitting their usual
brilliant phosphorescent light, sailing through the still and dark abyss
by the regular and synchronous pulsations of the minute fringed
arms of the whole polypi," appears to be based on a statement made
by Bohadsch in 1761, and picturesque though it be, is undoubtedly
erroneous.
The brilliant phosphorescence of many species of Pennatulacea has
been observed by many naturalists, and it is very probable that they
all exhibit this property to some degree. The phosphorescence
appears to be emitted by the mesenteric filaments of the autozooids,
but it is not yet determined whether the phenomenon is confined to
these organs or is more generally distributed.

The Pennatulacea are usually devoid of epizoites, but occasionally


the parasitic or semi-parasitic Entomostracan Lamippe is found in
the zooids. A small crab is also frequently found between the large
leaves of species of Pteroeides. The most remarkable case of
symbiosis, however, has recently been observed in the form of an
encrusting Gymnoblastic Hydroid[390] living on the free edge of the
leaves of a species of Ptilosarcus.

The order Pennatulacea is divided into four sections.

Sect. 1. Pennatuleae.—In this section the colony is distinctly


bilaterally symmetrical, and the autozooids are arranged in rows with
their body-walls fused to form leaves.

The genus Pteroeides, the representative genus of the family


Pteroeididae, is a fleshy Sea-pen found in shallow sea water in the
warm waters of the Pacific Ocean and in the Mediterranean. It has
large leaves with long spiny, projecting spicules, and the
siphonozooids are borne by the leaves. Pennatula, the
representative genus of the family Pennatulidae, has a wider
distribution in area and in depth. Pennatula phosphorea is a common
British species, found in depths of 10 to 20 fathoms in many
localities off our coasts. It is about 5 inches in length. There are
several varieties of this species distributed in Atlantic waters.
Pennatula grandis is a magnificent species found in Norwegian
fjords, in the Faeroe Channel, and off the northern coasts of N.
America, in depths of from 50 to 1255 fathoms. Specimens have
been obtained no less than 2½ feet in length. P. murrayi and P.
naresi are species of the genus found at depths of a few hundred
fathoms in tropical seas.

The genus Virgularia, belonging to the family Virgulariidae, is


represented in the British seas by V. mirabilis, a long slender Sea-
pen found in many localities off the Scottish coasts.

Sect. 2. Spicatae.—This section includes those Sea-pens in which


the autozooids are arranged bilaterally on the axial zooid in rows or
more irregularly, but do not unite to form leaves. It is a large section
and contains many widely divergent genera.

The family Funiculinidae is represented on our coasts by Funiculina


quadrangularis, a long and slender Sea-pen 2 to 3 feet in length. The
autozooids are arranged in oblique rows, and the siphonozooids are
on the ventral side of the rachis. There is one point of special interest
in this genus. The siphonozooids appear to change as the colony
grows and to become autozooids. If this is the case it may be more
correct to describe the genus as devoid of true siphonozooids.

The family Anthoptilidae contains the species Anthoptilum


grandiflorum, which has a wide distribution in depths of 130 to 500
fathoms in the N. and S. Atlantic Ocean. It is perhaps the largest of
all the Pennatulacea, specimens having been obtained from the
Cape of Good Hope over 4 feet long with expanded autozooids,
each more than half an inch in length.

The family Kophobelemnonidae contains a number of forms with


remarkably large autozooids arranged in irregular rows on the two
sides of the rachis. The siphonozooids are numerous and scattered,
and their position is indicated by small papilliform calices on the
coenenchym. The surface of these pens is usually rough, owing to
the presence of numerous coarse projecting spicules.
Kophobelemnon occurs in the Mediterranean in deep water, off the
coasts of Ireland and Scotland, and in other regions.

The family Umbellulidae contains some of the most remarkable and


interesting examples of the deep-sea fauna. The peduncle is very
long and the rachis stunted and expanded. The autozooids are of
great size, non-retractile, and arranged in a cluster or rosette on the
terminal rachis. There is a wide structural range between the
species. Some species have numerous large spicules, others have
none. In some species the siphonozooids have a single pinnate or
digitate tentacle, in others the siphonozooids are of the usual type.
Umbellula appears to be a somewhat rare but cosmopolitan genus in
deep water, extending from the Arctic to the Antarctic region in water
ranging from 200 to 2500 fathoms.

The interesting genus Chunella was discovered by the German


"Valdivia" Expedition at a depth of about 420 fathoms off the coast of
E. Africa, and subsequently by the Dutch "Siboga" Expedition at a
depth of about 500 fathoms in the Malay Archipelago. According to
Kükenthal,[391] this genus with another closely allied genus
Amphianthus should form a new section of Pennatulacea, the
Verticilladeae. Chunella has a long and very delicate rachis and
peduncle, and the former terminates in a single autozooid and has
five or six whorls of three autozooids, situated at considerable
distances from one another. Spicules are absent. The full description
of this genus has not yet been published, but it is clear that it
occupies a very isolated position in the order.

Fig. 160.—Renilla reniformis, a small specimen (34 mm.), showing the dorsal
side of the expanded rachis. A, autozooid; H, the mouth of the axial zooid;

You might also like