Giter Site home page Giter Site logo

fexpr's Introduction

fexpr

The fexpr package provides an interface to R's promise objects and dot (...) argument lists.

A "fexpr" is a type of nonstandard-evaluating function present in certain languages of the Lisp family. Fexprs can be used to to implement syntactic abstractions such as new types of control flow, or domain-specific languages. R's implementation of lazy evaluation in terms of promises essentially means that ordinary R functions are fexprs.

R's traditional tools for doing nonstandard evaluation (substitute, parent.frame, match.call) are non-orthogonal and tend to exhibit some scope problems in use. Using fexpr interface, nonstandard evaluating functions can be constructed using a more orthogonal, explicit style.

Access to promises

R functions evaluate their arguments lazily. When R invokes a function, the function arguments are lazily bound to promises. Each promise is a triple of three values: the environment in which the argument appeared, the expression that

The fexpr package allow inspection of each part of a promise.

Why to use arg_env, not parent.frame

Here's a problem that happens with traditional R metaprogramming....

Argument lists and ...

Promises can be put into a special type of list.

Variadic arguments (...) and missing values are two of the trickiest spots of R's semantics, and there are very few tools to work with them -- besides missing there's substitute and do.call, both of which are hairy and mostly serve other purposes. Mostly people treat ... as an opaque block to pass along to another function. This package contains a number of functions that let you work explicitly with ... lists, concatenating and subsetting them, while still allowing R's lazy-evaluation semantics to do the right thing. So a function using dots can decide whether and when to evaluate each of its unnamed arguments:

inSomeOrder <- function(...) invisible(list %()% sample(dots(...)))
inSomeOrder(print("Boing!"), print("Boom"), print("Tschack!"), print("Ping"),
            print("Zong"), print("Pssh"))
# [1] "Boing!"
# [1] "Zong"
# [1] "Ping"
# [1] "Boom"
# [1] "Pssh"
# [1] "Tschack!"

For a more pointed example, consider switch. Switch takes its first argument and uses it to decide which if its subsequent arguments to evaluate.

Consider trying to implement an R function that has the behavior of switch properly (not as a C function, and not inspecting the stack using match.call() or parent.frame() which are evil.) This is doable in pure R but wacky and slow -- the only way I can see to selectively evaluate one named argument is to build a function that takes that argument:

switch2 <- function(expr, ...) {
  n <- names(substitute(list(...)))[-1]
  if (!is.null(n))
      arglist <- as.pairlist(structure(
          rep(list(quote(expr=)), length(n)),
          names=n))
  else
      (arglist <- as.pairlist(alist(...=)))

  if (is.numeric(expr))
      body <- as.name(paste0("..", expr))
  else
      body <- as.name(expr)
  f <- eval(substitute(`function`(arglist, body),
                         list(arglist=arglist, body=body)))
  f(...)
}

But with a direct interface to manipulate dotlists, switch is easy:

switch3 <- function(expr, ...) {
  dots(...)[[expr]]
}

You may also use dots_unpack() to inspect the contents of as-yet-unevaluated dots objects, exposing R's promise mechanism:

x <- 1
y <- 2
d <- dots(a=x, b=y, c=x+y)
unpack(d)
#   name         envir  expr value
# a    a <environment>     x  NULL
# b    b <environment>     y  NULL
# c    c <environment> x + y  NULL
# > y <- 3
(function(b, ...) b) %()% d #force the "b" slot to evaluate
# [1] 3
unpack(d)
#   name         envir  expr value
# a    a <environment>     x  NULL
# b    b          NULL     y     3
# c    c <environment> x + y  NULL
c %()% d
# a b c
# 1 3 4
> unpack(d)
#   name envir  expr value
# a    a  NULL     x     1
# b    b  NULL     y     3
# c    c  NULL x + y     4

Missing arguments.

In R, function arguments may be "missing." When this happens...

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.