Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/moodymudskipper/dot3
Tools to Manipulate the Ellipsis Object
https://github.com/moodymudskipper/dot3
Last synced: 17 days ago
JSON representation
Tools to Manipulate the Ellipsis Object
- Host: GitHub
- URL: https://github.com/moodymudskipper/dot3
- Owner: moodymudskipper
- License: gpl-3.0
- Created: 2022-10-18T01:22:48.000Z (about 2 years ago)
- Default Branch: master
- Last Pushed: 2022-10-18T14:52:13.000Z (about 2 years ago)
- Last Synced: 2024-08-13T07:11:21.345Z (4 months ago)
- Language: R
- Size: 41 KB
- Stars: 3
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.Rmd
- License: LICENSE.md
Awesome Lists containing this project
- jimsghstars - moodymudskipper/dot3 - Tools to Manipulate the Ellipsis Object (R)
README
---
output: github_document
---```{r, include = FALSE}
knitr::opts_chunk$set(
collapse = TRUE,
comment = "#>",
fig.path = "man/figures/README-",
out.width = "100%"
)
```# dot3
[![Lifecycle: experimental](https://img.shields.io/badge/lifecycle-experimental-orange.svg)](https://lifecycle.r-lib.org/articles/stages.html#experimental)
{dot3} provides tools to manipulate the ellipsis object, also known as dots (`...`).
## Installation
Install with:
``` r
devtools::install_github("moodymudskipper/dot3")
```## Context: understanding dots
The ellipsis `...` in R is a special kind of object. It has the type `"..."`
(you can see it enumerated in the different base types in `?typeof`)
and cannot be manipulated like other objects.```{r, error = TRUE}
# This doesn't work
f <- function(...) ...
d <- f(a=1)# but this does
f <- function(...) get("...")
d <- f(a=1)# printing it doesn't say much
d
typeof(d)
```Though it's not typically done, and is hard to do without having R complain,
we can manipulate these objects```{r}
with(list(... = d), data.frame(..., b=2))
```Arguments defined through dots are defined lazily (only evaled when needed),
each of them has 3 important properties :* a name (optional)
* an expression
* an environment where the expression will be evaled when needed{dot3} offers tools to easily manipulate dots, this includes:
* creating them
* subsetting them and reordering them
* renaming their dot arguments
* setting evaluation environments
* combining them
* evaluating a dot argument selectively## Create and manipulate "dots" objects
We can create "dots" objects with the `dots()` function.
```{r}
library(dot3)
dots1 <- dots(a=x, x+y)
```The evaluation environment of these dot args will be the local environment,
if we need to set another environment we can use `dots_in_env()`We can use `with_dots()` to provide the dots as arguments to a function call.
```{r}
x <- 1
y <- 2
with_dots(dots1, c(...))
```The above is really equivalent to `with(list(... = dots1), c(...))`, just a bit
more compact and efficient.Objects created with `dots()` also have a class "dots", that allows printing, subsetting, combining, and naming.
```{r}
dots1 <- dots(a=x, x+y)# printing displays the argument positions, environments, names (if relevant), and expression
dots1# we can subset dots, this includes reordering them
dots1[2:1]# subsetting with `[[` or `$` evaluates the item in the relevant environment, without
# triggering evaluation of other elements of the "dots" object
dots1$a
dots1[[2]]# we can use c() to combine
dots2 <- dots(b = y)
dots3 <- c(dots1, dots2)# we can edit the names
names(dots3)[1] <- "X"
# and the environments
dots_env(dots3[1:2]) <- asNamespace("stats")
dots3
```In practice `dots()` will mostly be used inside of functions, to manipulate the
dot arguments originally provided to the function.```{r}
f <- function(...) {
dots1 <- dots(...)
dots2 <- dots(b = y)
dots3 <- dots(..., b = y)
list(
dots1 = dots1,
dots2 = dots2,
dots3 = dots3
)
}
f(a = x)
```## Convert arguments to/from dots
`endots()` creates a single argument `"dots"` object from an argument (or any object or
unevaled promise).`enarg()` creates an unevaled promise from a one argument `"dots"` object, *as a side effect*.
These names are inspired by the `en*()` family of functions of {rlang} (`enquo()`, `enexpr()` etc).
```{r, error = TRUE}
f <- function(x) {
dots1 <- endot(x)
dots1
}
f(y+z)g <- function(...) {
d <- dots(...)
enarg(d[1]) # create promise using name of dot argument
enarg(d[2], "z") # use provided name instead
message("not yet evaled")
x + z
}
g(x = 1, y = 2)
try(g(x = 1, y = stop()))
```## dots_expand
This function is used to support the syntax `fun(... = alist())`,
see example below:```{r}
subset2 <- function(...) {
dots_expand() # the only thing we need is this call before dots are used in the function
subset(...)
}# it still works as it would without the feature
subset2(cars, speed == 4)# we can provide all dot arguments to the `... =` argument
args <- alist(cars, speed == 4)
subset2(... = args)# or combine both ways
args <- alist(speed == 4)
subset2(cars, ... = args)
```This way arguments can easily be provided to a function without using `do.call()`,
it can be compared to the use of `!!!` in {rlang}, except that it will work
with lazily evaled arguments too.