{"id":13400957,"url":"https://github.com/egnha/nofrills","last_synced_at":"2025-04-10T02:56:35.297Z","repository":{"id":56934142,"uuid":"97501774","full_name":"egnha/nofrills","owner":"egnha","description":"Low-cost anonymous functions","archived":false,"fork":false,"pushed_at":"2022-02-24T11:07:26.000Z","size":508,"stargazers_count":40,"open_issues_count":0,"forks_count":2,"subscribers_count":3,"default_branch":"0.3.2","last_synced_at":"2025-03-18T07:09:31.587Z","etag":null,"topics":["anonymous-functions","currying","lambda-functions","partial-functions","quasiquotation","r"],"latest_commit_sha":null,"homepage":null,"language":"R","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/egnha.png","metadata":{"files":{"readme":"README.Rmd","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-07-17T17:06:53.000Z","updated_at":"2024-02-20T08:19:59.000Z","dependencies_parsed_at":"2022-08-21T06:50:33.065Z","dependency_job_id":null,"html_url":"https://github.com/egnha/nofrills","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/egnha%2Fnofrills","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/egnha%2Fnofrills/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/egnha%2Fnofrills/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/egnha%2Fnofrills/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/egnha","download_url":"https://codeload.github.com/egnha/nofrills/tar.gz/refs/heads/0.3.2","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248147702,"owners_count":21055545,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["anonymous-functions","currying","lambda-functions","partial-functions","quasiquotation","r"],"created_at":"2024-07-30T19:00:57.306Z","updated_at":"2025-04-10T02:56:35.277Z","avatar_url":"https://github.com/egnha.png","language":"R","funding_links":[],"categories":["R"],"sub_categories":[],"readme":"---\noutput: github_document\n---\n\n\u003c!-- README.md is generated from README.Rmd. Please edit that file --\u003e\n\n```{r, echo = FALSE}\nknitr::opts_chunk$set(\n  collapse = TRUE,\n  comment = \"#\u003e\",\n  fig.path = \"README-\"\n)\n```\n\n\u003e Unless you need `curry()` or `curry_fn()`, you should use the more versatile\n[gestalt](https://github.com/egnha/gestalt) package, which includes `fn()`.\n\n[![Travis-CI Build Status](https://travis-ci.org/egnha/nofrills.svg?branch=master)](https://travis-ci.org/egnha/nofrills)\n[![codecov](https://codecov.io/gh/egnha/nofrills/branch/master/graph/badge.svg)](https://app.codecov.io/gh/egnha/nofrills)\n[![CRAN_Status_Badge](https://www.r-pkg.org/badges/version/nofrills)](https://cran.r-project.org/package=nofrills)\n\n# nofrills \u003cimg src=\"inst/logo.png\" align=\"right\" /\u003e\n\n_Low-Cost Anonymous Functions_\n\n## Overview\n\n_nofrills_ is a lightweight R package that provides `fn()`, a more powerful \nvariation of `function()` that:\n\n  - **costs less** — enables tidyverse quasiquotation so you don’t pay the price\n    of [functional impurity](#pure-functions-via-quasiquotation)\n    \n  - has the **same great taste** — supports a superset of `function()`’s syntax\n    and capabilities\n    \n  - is **less filling** —\n    ```{r, eval = FALSE}\n    fn(x, y = 1 ~ x + y)\n    ```\n    is equivalent to\n    ```{r, eval = FALSE}\n    function(x, y = 1) x + y\n    ```\n\n## Installation\n\n```{r, eval = FALSE}\ninstall.packages(\"nofrills\")\n```\n\nAlternatively, install the development version from GitHub:\n\n```{r gh-installation, eval = FALSE}\n# install.packages(\"devtools\")\ndevtools::install_github(\"egnha/nofrills\")\n```\n\n## Usage\n\n```{r, echo = FALSE}\nlibrary(nofrills)\n```\n\n### Same syntax as `function()` but shorter\n\n```{r}\nfn(x ~ x + 1)\n\nfn(x, y ~ x + y)\n\nfn(x, y = 2 ~ x + y)\n\nfn(x, y = 1, ... ~ log(x + y, ...))\n\n# the only exception, cf. alist()\nfn(x, ... = , y ~ log(x + y, ...))\n\nfn(~ NA)\n```\n\n### Supports quasiquotation\n\n#### Unquote values\n\n```{r}\nz \u003c- 0\n\nfn(x, y = !!z ~ x + y)\n\nfn(x ~ x \u003e !!z)\n```\n\n#### Unquote argument names\n\n```{r}\narg \u003c- \"y\"\n\nfn(x, !!arg := 0 ~ x + !!as.name(arg))\n```\n\n#### Splice in argument lists\n\n```{r}\nargs \u003c- alist(x, y = 0)\n\nfn(!!!args, ~ x + y)  # note the one-sided formula\n```\n\n#### Literally unquote with `QUQ()`, `QUQS()`\n\n```{r message = FALSE}\nlibrary(dplyr)\n\nsummariser \u003c- quote(mean)\n\nmy_summarise \u003c- fn(df, ... ~ {\n  group_by \u003c- quos(...)\n  df %\u003e%\n    group_by(QUQS(group_by)) %\u003e%\n    summarise(a = (!!summariser)(a))\n})\n\nmy_summarise\n```\n(Source:\n[_Programming with dplyr_](https://dplyr.tidyverse.org/articles/programming.html))\n\n### [Curry](https://en.wikipedia.org/wiki/Currying) functions\n\n#### Declare a curried function with `curry_fn()`\n\nThe syntax is the same as `fn()`. Using the literal unquoting operators `QUQ()`,\n`QUQS()`, you can “delay” unquoting to embed argument values in the innermost\nfunction:\n\n```{r}\ncompare_to \u003c- curry_fn(target, x ~ identical(x, QUQ(target)))\nis_this \u003c- compare_to(\"this\")\n\n# The embedded value \"this\" renders the source comprehensible\nis_this\n```\n\n#### Curry a function with `curry()`\n\n```{r}\ncurry(function(x, y, z = 0) x + y + z)\n\ndouble \u003c- curry(`*`)(2)\ndouble(3)\n```\n\n## Pure functions via quasiquotation\n\nFunctions in R are generally\n[impure](https://en.wikipedia.org/wiki/Pure_function), i.e., the return value of\na function will _not_ in general be determined by the value of its inputs alone.\nThis is because a function may depend on mutable objects in its [lexical\nscope](https://adv-r.hadley.nz/functions.html#lexical-scoping). Normally this\nisn’t an issue. But if you are working interactively and sourcing files into the\nglobal environment, say, or using a notebook interface (like Jupyter or R \nNotebook), it can be tricky to ensure that you haven’t unwittingly mutated an\nobject that an earlier function depends upon.\n\n  - Consider the following function:\n    ```{r}\n    a \u003c- 1\n    foo \u003c- function(x) x + a\n    ```\n    What is the value of `foo(1)`? It is not necessarily `2` because the value\n    of `a` may have changed between the _creation_ of `foo()` and the _calling_\n    of `foo(1)`:\n    ```{r}\n    foo(1)\n    \n    a \u003c- 0\n    \n    foo(1)\n    ```\n    In other words, `foo()` is impure because the value of `foo(x)` depends not\n    only on the value of `x` but also on the _externally mutable_ value of `a`.\n    \n`fn()` enables you to write **pure(r)** functions by using quasiquotation to\neliminate such indeterminacy.\n\n  - With `fn()`, you can unquote `a` to capture its value at the point of\n    creation:\n    ```{r}\n    a \u003c- 1\n    foo \u003c- fn(x ~ x + !!a)\n    ```\n    Now `foo()` is a pure function, unaffected by changes in its lexical scope:\n    ```{r}\n    foo(1)\n    \n    a \u003c- 0\n    \n    foo(1)\n    ```\n\n## Alternatives to nofrills\n\nAlternative anonymous-function constructors (which don’t support quasiquotation)\ninclude:\n\n  - [`pryr::f()`](https://github.com/hadley/pryr)\n  - [`lambda::f()`](https://github.com/jimhester/lambda)\n  - [`rlang::as_function()`](https://rlang.r-lib.org/reference/as_function.html)\n\n## Acknowledgement\n\nThe [rlang](https://github.com/r-lib/rlang) package by [Lionel\nHenry](https://github.com/lionel-) and [Hadley \nWickham](https://github.com/hadley) makes nofrills possible. Crucially, rlang\nprovides the engine for quasiquotation and expression capture.\n\n## License\n\nMIT Copyright © 2017–22 [Eugene Ha](https://github.com/egnha)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fegnha%2Fnofrills","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fegnha%2Fnofrills","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fegnha%2Fnofrills/lists"}