I came across this example from an R tutorial recently and I found this syntax really odd because it hints towards normal order reduction where arguments are wrapped / delayed. In applicative order reduction something like this should result in all the strings printing.
switch(grade,
"A" = print("Great"),
"B" = print("Good"),
"C" = print("Ok"),
"D" = print("Bad"),
"F" = print("Terrible"),
print("No Such Grade"))
Was wondering if anyone is privy and familiar with how R implements this?
Arguments to functions, including switch, are passed as promises which are forced, i.e. evaluated, only when actually used. See https://cran.r-project.org/doc/manuals/R-ints.html#Argument-evaluation
A promise has several parts. Its value slot is filled in the first time it is forced (i.e. accessed). Until then it just exists as unevaluated code and its environment as well as components which indicate that it has not been evaluated.
f does not force x:
library(pryr)
f <- function(x) promise_info(x)
f(3+pi)
giving:
$code
3 + pi
$env
<environment: R_GlobalEnv>
$evaled
[1] FALSE
$value
NULL
g forces x:
g <- function(x) { force(x); promise_info(x) }
g(3 + pi)
giving:
$code
3 + pi
$env
NULL
$evaled
[1] TRUE
$value
[1] 6.141593
Related
I built a function that print results in R console.
The function works within a loop.
Several prints are made when the function is used.
I'd like to add void/space line between printed results
thx!
short example of data and working loop :
test <- c("A","B","C")
for (i in 1:length(test)){
print(test[i])
print("")
}
actual output :
[1] "A"
[1] ""
[1] "B"
[1] ""
[1] "C"
[1] ""
desired output :
[1] "A"
[1] "B"
[1] "C"
The comments under your question already provide hacks how to solve your problem. Nevertheless, it is worthwhile to mention some problems of your solution.
First, you are using a for loop, which is notoriously slow in R. If possible, it is always better to use a builtin vectorized function, e.g. (To add a blank line, just use "\n\n" instead of "\n"):
> cat(test, sep="\n")
A
B
C
Moreover, it might generally be preferable, for legibility reasons, to use formatted output with sprintf and cat, e.g.
> for (i in 1:length(test)) {
> cat(sprintf("test[%i] = %s\n", i, test[i]))
> }
test[1] = A
test[2] = B
test[3] = C
And because sprintf is a vectorized function, too, the same can be achieved without a for loop:
> cat(sprintf("test[%i] = %s\n", 1:length(test), test), sep="")
test[1] = A
test[2] = B
test[3] = C
Given an rlang expression:
expr1 <- rlang::expr({
d <- a + b
})
How to retrieve the names of the objects refered to within the expression ?
> extractObjects(expr1)
[1] "d" "a" "b"
Better yet, how to retrieve the object names and categorise them by "required"(input) and "created"(output) ?
> extractObjects(expr1)
$created
[1] "d"
$required
[1] "a" "b"
The base function all.vars does this:
〉all.vars(expr1)
[1] "d" "a" "b"
Alternatively, you can use all.names to get all names in the expression rather than just those that aren’t used as calls or operators:
〉all.names(expr1)
[1] "{" "<-" "d" "+" "a" "b"
Don’t be misled: this result is correct! All of these appear in the expression, not just a, b and d.
But it may not be what you want.
In fact, I’m assuming what you want corresponds to the leaf tokens in the abstract syntax tree (AST) — in other words, everything except function calls (and operators, which are also function calls).
The syntax tree for your expression looks as follows:1
{
|
<-
/\
d +
/ \
a b
Getting this information means walking the AST:
leaf_nodes = function (expr) {
if(is.call(expr)) {
unlist(lapply(as.list(expr)[-1L], leaf_nodes))
} else {
as.character(expr)
}
}
〉leaf_nodes(expr1)
[1] "d" "a" "b"
Thanks to the AST representation we can also find inputs and outputs:
is_assignment = function (expr) {
is.call(expr) && as.character(expr[[1L]]) %in% c('=', '<-', '<<-', 'assign')
}
vars_in_assign = function (expr) {
if (is.call(expr) && identical(expr[[1L]], quote(`{`))) {
vars_in_assign(expr[[2L]])
} else if (is_assignment(expr)) {
list(created = all.vars(expr[[2L]]), required = all.vars(expr[[3L]]))
} else {
stop('Expression is not an assignment')
}
}
〉vars_in_assign(expr1)
$created
[1] "d"
$required
[1] "a" "b"
Note that this function does not handle complex assignments (i.e. stuff like d[x] <- a + b or f(d) <- a + b very well.
1 lobstr::ast shows the syntax tree differently, namely as
█─`{`
└─█─`<-`
├─d
└─█─`+`
├─a
└─b
… but the above representation is more conventional outside R, and I find it more intuitive.
Another solution is to extract the abstract symbolic tree explicitly:
getAST <- function(ee) purrr::map_if(as.list(ee), is.call, getAST)
str(getAST(expr1))
# List of 2
# $ : symbol {
# $ :List of 3
# ..$ : symbol <-
# ..$ : symbol d
# ..$ :List of 3
# .. ..$ : symbol +
# .. ..$ : symbol a
# .. ..$ : symbol b
Then traverse the AST to find the assignment(s):
extractObjects <- function(ast)
{
## Ensure that there is at least one node
if( length(ast) == 0 ) stop("Provide an AST")
## If we are working with the assigment
if( identical(ast[[1]], as.name("<-")) ) {
## Separate the LHS and RHS
list(created = as.character(ast[[2]]),
required = sapply(unlist(ast[[3]]), as.character))
} else {
## Otherwise recurse to find all assignments
rc <- purrr::map(ast[-1], extractObjects)
## If there was only one assignment, simplify reporting
if( length(rc) == 1 ) purrr::flatten(rc)
else rc
}
}
extractObjects( getAST(expr1) )
# $created
# [1] "d"
#
# $required
# [1] "+" "a" "b"
You may then filter math operators out, if needed.
This is an interesting one. I think that conceptually, it might not be clear in ALL possible expressions what exactly is input and output. If you look at the so called abstract syntax tree (AST), which you can visualize with lobstr::ast(), it looks like this.
So in simple cases when you always have LHS <- operations on RHS variables, if you iterate over the AST, you will always get the LST right after the <- operator. If you assign z <- rlang::expr(d <- a+b), then z behaves like a list and you can for example do the following:
z <- rlang::expr(d <- a+b)
for (i in 1:length(z)) {
if (is.symbol(z[[i]])) {
print(paste("Element", i, "of z:", z[[i]], "is of type", typeof(z[[i]])))
if (grepl("[[:alnum:]]", z[[i]])) {print(paste("Seems like", z[[i]], "is a variable"))}
} else {
for (j in 1:length(z[[i]])){
print(paste("Element", j, paste0("of z[[",i,"]]:"), z[[i]][[j]], "is of type", typeof(z[[i]][[j]])))
if (grepl("[[:alnum:]]", z[[i]][[j]])) {print(paste("Seems like", z[[i]][[j]], "is a variable"))}
}
}
}
#> [1] "Element 1 of z: <- is of type symbol"
#> [1] "Element 2 of z: d is of type symbol"
#> [1] "Seems like d is a variable"
#> [1] "Element 1 of z[[3]]: + is of type symbol"
#> [1] "Element 2 of z[[3]]: a is of type symbol"
#> [1] "Seems like a is a variable"
#> [1] "Element 3 of z[[3]]: b is of type symbol"
#> [1] "Seems like b is a variable"
Created on 2020-09-03 by the reprex package (v0.3.0)
As you can see these trees can quickly get complicated and nested. So in a simple case like in your example, assuming that variables are using alphanumeric representations, we can kind of identify what the "objects" (as you call them) are and what are operators (which don't match the [[:alnum:]] regex). As you can see the type cannot be used to distinguish between objects and operators since it is always symbol (btw z below is a language as is z[[3]] which is why we can condition on whether z[[i]] is a symbol or not and if not, dig a level deeper). You could then (at your peril) try to classify that the objects that appear immediately after a <- are "outputs" and the rest are "inputs" but I don't have too much confidence in this, especially for more complex expressions.
In short, this is all very speculative.
For an arbitrary function
f <- function(x, y = 3){
z <- x + y
z^2
}
I want to be able take the argument names of f
> argument_names(f)
[1] "x" "y"
Is this possible?
formalArgs and formals are two functions that would be useful in this case. If you just want the parameter names then formalArgs will be more useful as it just gives the names and ignores any defaults. formals gives a list as the output and provides the parameter name as the name of the element in the list and the default as the value of the element.
f <- function(x, y = 3){
z <- x + y
z^2
}
> formalArgs(f)
[1] "x" "y"
> formals(f)
$x
$y
[1] 3
My first inclination was to just suggest formals and if you just wanted the names of the parameters you could use names like names(formals(f)). The formalArgs function just is a wrapper that does that for you so either way works.
Edit: Note that technically primitive functions don't have "formals" so this method will return NULL if used on primitives. A way around that is to first wrap the function in args before passing to formalArgs. This works regardless of it the function is primitive or not.
> # formalArgs will work for non-primitives but not primitives
> formalArgs(f)
[1] "x" "y"
> formalArgs(sum)
NULL
> # But wrapping the function in args first will work in either case
> formalArgs(args(f))
[1] "x" "y"
> formalArgs(args(sum))
[1] "..." "na.rm"
Is there a way to write pipelined functions in R where the result of one function passes immediately into the next? I'm coming from F# and really appreciated this ability but have not found how to do it in R. It should be simple but I can't find how. In F# it would look something like this:
let complexFunction x =
x |> square
|> add 5
|> toString
In this case the input would be squared, then have 5 added to it and then converted to a string. I'm wanting to be able to do something similar in R but don't know how. I've searched for how to do something like this but have not come across anything. I'm wanting this for importing data because I typically have to import it and then filter. Right now I do this in multiple steps and would really like to be able to do something the way you would in F# with pipelines.
Here is a functional programming approach using Reduce. It is in fact an example from ?Reduce
square <- function(x) x^2
add_5 <- function(x) x+5
x <- 1:5
## Iterative function application:
Funcall <- function(f, ...) f(...)
Reduce(Funcall, list(as.character, add_5, square,x), right = TRUE)
## [1] "6" "9" "14" "21" "30"
Or even more simply using the functional package and Compose
This is nice as it will create the function for you
library(functional)
do_stuff <- Compose(square,add_5,as.character )
do_stuff(1:5)
## [1] "6" "9" "14" "21" "30"
I note that I would not consider either of these approaches idiomatically R ish (if that is even a phrase)
We can use Compose from the functional package to create our own binary operator that does something similar to what you want
# Define our helper functions
square <- function(x){x^2}
add5 <- function(x){x + 5}
# functional contains Compose
library(functional)
# Define our binary operator
"%|>%" <- Compose
# Create our complexFunction by 'piping' our functions
complexFunction <- square %|>% add5 %|>% as.character
complexFunction(1:5)
#[1] "6" "9" "14" "21" "30"
# previously had this until flodel pointed out
# that the above was sufficient
#"%|>%" <- function(fun1, fun2){ Compose(fun1, fun2) }
I guess we could technically do this without requiring the functional package - but it feels so right using Compose for this task.
"%|>%" <- function(fun1, fun2){
function(x){fun2(fun1(x))}
}
complexFunction <- square %|>% add5 %|>% as.character
complexFunction(1:5)
#[1] "6" "9" "14" "21" "30"
I think that you might just want to write a function to do the steps you desire.
complexFunction <- function(x) {
as.character(x^2 + 5)
}
Then just call complexFunction(x).
Edit to show what R is doing internally (#mnel) -- The way R parses the and evaluates as.character(x^2 + 5) does what you want
You can use codetools to investigate what R to see how the values are being passed to eachother
flattenAssignment(quote(as.character(x^2+5)))
[[1]]
[[1]][[1]]
x
[[1]][[2]]
`*tmp*`^2
[[1]][[3]]
`*tmp*` + 5
[[2]]
[[2]][[1]]
`as.character<-`(`*tmp*`, value = `*tmpv*`)
[[2]][[2]]
`+<-`(`*tmp*`, 5, value = `*tmpv*`)
[[2]][[3]]
`^<-`(x, 2, value = `*tmpv*`)
Or you can get the Lisp style representation to see how it is parsed (and the results passed)
showTree(quote(as.character(x^2+5)))
(as.character (+ (^ x 2) 5))
Since this question was asked, the magrittr pipe has become enormously popular in R. So your example would be:
library (magrittr)
fx <- function (x) {
x %>%
`^` (2) %>%
`+` (5) %>%
as.character ()
}
Note that the backquote notation is because I'm literally using R's built-in functions and I need to specially quote them to use them in this manner. More normally-named functions (like exp or if I'd created a helper function add) wouldn't need backquotes and would appear more like your example.
Note also that %>% passes the incoming value as the first argument to the next function automatically, though you can change this. Note also that an R function returns the last value calculated so I don't need to return or assign the calculation in order to return it.
This is a lot like the nice special operators defined by other answers, but it uses a particular function that's widely used in R now.
This works for R pretty similar in F#:
"%|>%" <- function(x, fun){
if(is.function(x)) {
function(...) fun(x(...))
} else {
fun(x)
}
}
I am looking for the reverse of get().
Given an object name, I wish to have the character string representing that object extracted directly from the object.
Trivial example with foo being the placeholder for the function I am looking for.
z <- data.frame(x=1:10, y=1:10)
test <- function(a){
mean.x <- mean(a$x)
print(foo(a))
return(mean.x)}
test(z)
Would print:
"z"
My work around, which is harder to implement in my current problem is:
test <- function(a="z"){
mean.x <- mean(get(a)$x)
print(a)
return(mean.x)}
test("z")
The old deparse-substitute trick:
a<-data.frame(x=1:10,y=1:10)
test<-function(z){
mean.x<-mean(z$x)
nm <-deparse(substitute(z))
print(nm)
return(mean.x)}
test(a)
#[1] "a" ... this is the side-effect of the print() call
# ... you could have done something useful with that character value
#[1] 5.5 ... this is the result of the function call
Edit: Ran it with the new test-object
Note: this will not succeed inside a local function when a set of list items are passed from the first argument to lapply (and it also fails when an object is passed from a list given to a for-loop.) You would be able to extract the ".Names"-attribute and the order of processing from the structure result, if it were a named vector that were being processed.
> lapply( list(a=4,b=5), function(x) {nm <- deparse(substitute(x)); strsplit(nm, '\\[')} )
$a # This "a" and the next one in the print output are put in after processing
$a[[1]]
[1] "X" "" "1L]]" # Notice that there was no "a"
$b
$b[[1]]
[1] "X" "" "2L]]"
> lapply( c(a=4,b=5), function(x) {nm <- deparse(substitute(x)); strsplit(nm, '\\[')} )
$a
$a[[1]] # but it's theoretically possible to extract when its an atomic vector
[1] "structure(c(4, 5), .Names = c(\"a\", \"b\"))" ""
[3] "1L]]"
$b
$b[[1]]
[1] "structure(c(4, 5), .Names = c(\"a\", \"b\"))" ""
[3] "2L]]"
deparse(quote(var))
My intuitive understanding
In which the quote freeze the var or expression from evaluation
and the deparse function which is the inverse of parse function makes that freezed symbol back to String
Note that for print methods the behavior can be different.
print.foo=function(x){ print(deparse(substitute(x))) }
test = list(a=1, b=2)
class(test)="foo"
#this shows "test" as expected
print(test)
#this (just typing 'test' on the R command line)
test
#shows
#"structure(list(a = 1, b = 2), .Names = c(\"a\", \"b\"), class = \"foo\")"
Other comments I've seen on forums suggests that the last behavior is unavoidable. This is unfortunate if you are writing print methods for packages.
To elaborate on Eli Holmes' answer:
myfunc works beautifully
I was tempted to call it within another function (as discussed in his Aug 15, '20 comment)
Fail
Within a function, coded directly (rather than called from an external function), the deparse(substitute() trick works well.
This is all implicit in his answer, but for the benefit of peeps with my degree of obliviousness, I wanted to spell it out.
an_object <- mtcars
myfunc <- function(x) deparse(substitute(x))
myfunc(an_object)
#> [1] "an_object"
# called within another function
wrapper <- function(x){
myfunc(x)
}
wrapper(an_object)
#> [1] "x"