Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/egnha/nofrills
Low-cost anonymous functions
https://github.com/egnha/nofrills
anonymous-functions currying lambda-functions partial-functions quasiquotation r
Last synced: 26 days ago
JSON representation
Low-cost anonymous functions
- Host: GitHub
- URL: https://github.com/egnha/nofrills
- Owner: egnha
- License: other
- Created: 2017-07-17T17:06:53.000Z (over 7 years ago)
- Default Branch: 0.3.2
- Last Pushed: 2022-02-24T11:07:26.000Z (over 2 years ago)
- Last Synced: 2024-09-30T02:43:21.316Z (about 1 month ago)
- Topics: anonymous-functions, currying, lambda-functions, partial-functions, quasiquotation, r
- Language: R
- Size: 496 KB
- Stars: 40
- Watchers: 3
- Forks: 2
- Open Issues: 0
-
Metadata Files:
- Readme: README.Rmd
- License: LICENSE
Awesome Lists containing this project
README
---
output: github_document
---```{r, echo = FALSE}
knitr::opts_chunk$set(
collapse = TRUE,
comment = "#>",
fig.path = "README-"
)
```> Unless you need `curry()` or `curry_fn()`, you should use the more versatile
[gestalt](https://github.com/egnha/gestalt) package, which includes `fn()`.[![Travis-CI Build Status](https://travis-ci.org/egnha/nofrills.svg?branch=master)](https://travis-ci.org/egnha/nofrills)
[![codecov](https://codecov.io/gh/egnha/nofrills/branch/master/graph/badge.svg)](https://app.codecov.io/gh/egnha/nofrills)
[![CRAN_Status_Badge](https://www.r-pkg.org/badges/version/nofrills)](https://cran.r-project.org/package=nofrills)# nofrills
_Low-Cost Anonymous Functions_
## Overview
_nofrills_ is a lightweight R package that provides `fn()`, a more powerful
variation of `function()` that:- **costs less** — enables tidyverse quasiquotation so you don’t pay the price
of [functional impurity](#pure-functions-via-quasiquotation)
- has the **same great taste** — supports a superset of `function()`’s syntax
and capabilities
- is **less filling** —
```{r, eval = FALSE}
fn(x, y = 1 ~ x + y)
```
is equivalent to
```{r, eval = FALSE}
function(x, y = 1) x + y
```## Installation
```{r, eval = FALSE}
install.packages("nofrills")
```Alternatively, install the development version from GitHub:
```{r gh-installation, eval = FALSE}
# install.packages("devtools")
devtools::install_github("egnha/nofrills")
```## Usage
```{r, echo = FALSE}
library(nofrills)
```### Same syntax as `function()` but shorter
```{r}
fn(x ~ x + 1)fn(x, y ~ x + y)
fn(x, y = 2 ~ x + y)
fn(x, y = 1, ... ~ log(x + y, ...))
# the only exception, cf. alist()
fn(x, ... = , y ~ log(x + y, ...))fn(~ NA)
```### Supports quasiquotation
#### Unquote values
```{r}
z <- 0fn(x, y = !!z ~ x + y)
fn(x ~ x > !!z)
```#### Unquote argument names
```{r}
arg <- "y"fn(x, !!arg := 0 ~ x + !!as.name(arg))
```#### Splice in argument lists
```{r}
args <- alist(x, y = 0)fn(!!!args, ~ x + y) # note the one-sided formula
```#### Literally unquote with `QUQ()`, `QUQS()`
```{r message = FALSE}
library(dplyr)summariser <- quote(mean)
my_summarise <- fn(df, ... ~ {
group_by <- quos(...)
df %>%
group_by(QUQS(group_by)) %>%
summarise(a = (!!summariser)(a))
})my_summarise
```
(Source:
[_Programming with dplyr_](https://dplyr.tidyverse.org/articles/programming.html))### [Curry](https://en.wikipedia.org/wiki/Currying) functions
#### Declare a curried function with `curry_fn()`
The syntax is the same as `fn()`. Using the literal unquoting operators `QUQ()`,
`QUQS()`, you can “delay” unquoting to embed argument values in the innermost
function:```{r}
compare_to <- curry_fn(target, x ~ identical(x, QUQ(target)))
is_this <- compare_to("this")# The embedded value "this" renders the source comprehensible
is_this
```#### Curry a function with `curry()`
```{r}
curry(function(x, y, z = 0) x + y + z)double <- curry(`*`)(2)
double(3)
```## Pure functions via quasiquotation
Functions in R are generally
[impure](https://en.wikipedia.org/wiki/Pure_function), i.e., the return value of
a function will _not_ in general be determined by the value of its inputs alone.
This is because a function may depend on mutable objects in its [lexical
scope](https://adv-r.hadley.nz/functions.html#lexical-scoping). Normally this
isn’t an issue. But if you are working interactively and sourcing files into the
global environment, say, or using a notebook interface (like Jupyter or R
Notebook), it can be tricky to ensure that you haven’t unwittingly mutated an
object that an earlier function depends upon.- Consider the following function:
```{r}
a <- 1
foo <- function(x) x + a
```
What is the value of `foo(1)`? It is not necessarily `2` because the value
of `a` may have changed between the _creation_ of `foo()` and the _calling_
of `foo(1)`:
```{r}
foo(1)
a <- 0
foo(1)
```
In other words, `foo()` is impure because the value of `foo(x)` depends not
only on the value of `x` but also on the _externally mutable_ value of `a`.
`fn()` enables you to write **pure(r)** functions by using quasiquotation to
eliminate such indeterminacy.- With `fn()`, you can unquote `a` to capture its value at the point of
creation:
```{r}
a <- 1
foo <- fn(x ~ x + !!a)
```
Now `foo()` is a pure function, unaffected by changes in its lexical scope:
```{r}
foo(1)
a <- 0
foo(1)
```## Alternatives to nofrills
Alternative anonymous-function constructors (which don’t support quasiquotation)
include:- [`pryr::f()`](https://github.com/hadley/pryr)
- [`lambda::f()`](https://github.com/jimhester/lambda)
- [`rlang::as_function()`](https://rlang.r-lib.org/reference/as_function.html)## Acknowledgement
The [rlang](https://github.com/r-lib/rlang) package by [Lionel
Henry](https://github.com/lionel-) and [Hadley
Wickham](https://github.com/hadley) makes nofrills possible. Crucially, rlang
provides the engine for quasiquotation and expression capture.## License
MIT Copyright © 2017–22 [Eugene Ha](https://github.com/egnha)