R: Common Higher-Order Functions in Functional Programming...

funprog {base} | R Documentation

## Common Higher-Order Functions in Functional Programming Languages

### Description

`Reduce` uses a binary function to successively combine the elements of a given vector and a possibly given initial value. `Filter` extracts the elements of a vector for which a predicate (logical) function gives true. `Find` and `Position` give the first or last such element and its position in the vector, respectively. `Map` applies a function to the corresponding elements of given vectors. `Negate` creates the negation of a given function.

### Usage

    Reduce(f, x, init, right = FALSE, accumulate = FALSE)
    Filter(f, x)
    Find(f, x, right = FALSE, nomatch = NULL)
    Map(f, ...)
    Negate(f)
    Position(f, x, right = FALSE, nomatch = NA_integer_)

### Arguments

`f` | a function of the appropriate arity (binary for `Reduce`, unary for `Filter`, `Find` and `Position`, k-ary for `Map` if this is called with k arguments). An arbitrary predicate function for `Negate`.
`x` | a vector.
`init` | an R object of the same kind as the elements of `x`.
`right` | a logical indicating whether to proceed from left to right (default) or from right to left.
`accumulate` | a logical indicating whether the successive reduce combinations should be accumulated. By default, only the final combination is used.
`nomatch` | the value to be returned in the case when “no match” (no element satisfying the predicate) is found.
`...` | vectors.

### Details

If `init` is given, `Reduce` logically adds it to the start (when proceeding left to right) or the end of `x`, respectively. If this possibly augmented vector v has n > 1 elements, `Reduce` successively applies f to the elements of v from left to right or right to left, respectively. I.e., a left reduce computes l_1 = f(v_1, v_2), l_2 = f(l_1, v_3), etc., and returns l_{n-1} = f(l_{n-2}, v_n), and a right reduce does r_{n-1} = f(v_{n-1}, v_n), r_{n-2} = f(v_{n-2}, r_{n-1}) and returns r_1 = f(v_1, r_2). (E.g., if v is the sequence (2, 3, 4) and f is division, left and right reduce give (2 / 3) / 4 = 1/6 and 2 / (3 / 4) = 8/3, respectively.) If v has only a single element, this is returned; if there are no elements, `NULL` is returned. Thus, it is ensured that `f` is always called with 2 arguments.

The current implementation is non-recursive to ensure stability and scalability.

`Reduce` is patterned after Common Lisp's `reduce`. A reduce is also known as a fold (e.g., in Haskell) or an accumulate (e.g., in the C++ Standard Template Library). The accumulative version corresponds to Haskell's scan functions.

`Filter` applies the unary predicate function `f` to each element of `x`, coercing to logical if necessary, and returns the subset of `x` for which this gives true. Note that possible `NA` values are currently always taken as false; control over `NA` handling may be added in the future. `Filter` corresponds to `filter` in Haskell or `remove-if-not` in Common Lisp.

`Find` and `Position` are patterned after Common Lisp's `find-if` and `position-if`, respectively. If there is an element for which the predicate function gives true, then the first or last such element or its position is returned depending on whether `right` is false (default) or true, respectively. If there is no such element, the value specified by `nomatch` is returned. The current implementation is not optimized for performance.

`Map` is a simple wrapper to `mapply` which does not attempt to simplify the result, similar to Common Lisp's `mapcar` (with arguments being recycled, however). Future versions may allow some control of the result type.

`Negate` corresponds to Common Lisp's `complement`. Given a (predicate) function `f`, it creates a function which returns the logical negation of what `f` returns.

### See Also

Function `clusterMap` and `mcmapply` (not Windows) in package parallel provide parallel versions of `Map`.

### Examples

    ## A general-purpose adder:
    add <- function(x) Reduce("+", x)
    add(list(1, 2, 3))
    ## Like sum(), but can also used for adding matrices etc., as it will
    ## use the appropriate '+' method in each reduction step.
    ## More generally, many generics meant to work on arbitrarily many
    ## arguments can be defined via reduction:
    FOO <- function(...) Reduce(FOO2, list(...))
    FOO2 <- function(x, y) UseMethod("FOO2")
    ## FOO() methods can then be provided via FOO2() methods.

    ## A general-purpose cumulative adder:
    cadd <- function(x) Reduce("+", x, accumulate = TRUE)
    cadd(seq_len(7))

    ## A simple function to compute continued fractions:
    cfrac <- function(x) Reduce(function(u, v) u + 1 / v, x, right = TRUE)
    ## Continued fraction approximation for pi:
    cfrac(c(3, 7, 15, 1, 292))
    ## Continued fraction approximation for Euler's number (e):
    cfrac(c(2, 1, 2, 1, 1, 4, 1, 1, 6, 1, 1, 8))

    ## Iterative function application:
    Funcall <- function(f, ...) f(...)
    ## Compute log(exp(acos(cos(0))))
    Reduce(Funcall, list(log, exp, acos, cos), 0, right = TRUE)
    ## n-fold iterate of a function, functional style:
    Iterate <- function(f, n = 1)
        function(x) Reduce(Funcall, rep.int(list(f), n), x, right = TRUE)
    ## Continued fraction approximation to the golden ratio:
    Iterate(function(x) 1 + 1 / x, 30)(1)
    ## which is the same as
    cfrac(rep.int(1, 31))
    ## Computing square root approximations for x as fixed points of the
    ## function t |-> (t + x / t) / 2, as a function of the initial value:
    asqrt <- function(x, n) Iterate(function(t) (t + x / t) / 2, n)
    asqrt(2, 30)(10) # Starting from a positive value => +sqrt(2)
    asqrt(2, 30)(-1) # Starting from a negative value => -sqrt(2)

    ## A list of all functions in the base environment:
    funs <- Filter(is.function, sapply(ls(baseenv()), get, baseenv()))
    ## Functions in base with more than 10 arguments:
    names(Filter(function(f) length(formals(f)) > 10, funs))
    ## Number of functions in base with a '...' argument:
    length(Filter(function(f)
                  any(names(formals(f)) %in% "..."),
                  funs))

    ## Find all objects in the base environment which are *not* functions:
    Filter(Negate(is.function),  sapply(ls(baseenv()), get, baseenv()))

[Package base version 3.5.1 Index]