I'm trying to use possibly() to print the argument x as a message when the function sum() fails.
library(purrr)
t <- function(x) {
p <- possibly(sum, otherwise = message(x))
p(x)
}
However, I would not expect the below to retrieve any message, since sum() doesn't fail:
> t(1)
1
[1] 1
Instead, the script below works as expected: sum() fails, thus t() prints the message 'a'
> t('a')
a
NULL
As noted in the other answer, possibly simply does something quite different from what you want.
What you want is tryCatch (part of base R):
t <- function(x) {
tryCatch(sum(x), error = function (.) message(x))
}
t(1)
# [1] 1
t('a')
# a
The argument otherwise of the function purrr::possibly is a value but message(x) is an R expression. According to the documentation:
These functions wrap functions so that instead of generating side effects through printed output, messages, warnings, and errors, they return enhanced output.
Related
I'd like to wrap around the checkmate library's qassert to check multiple variable's specification at a time. Importantly, I'd like assertion errors to still report the variable name that's out of spec.
So I create checkargs to loop through input arguments. But to get the variable passed on to qassert, I use the same code for each loop -- that ambigious code string gets used for for the error message instead of the problematic variable name.
qassert() (via vname()) is getting what to display in the assertion error like deparse(eval.parent(substitute(substitute(x))). Is there any way to box up get(var) such that that R will see e.g. 'x' on deparse instead?
At least one work around is eval(parse()). But something like checkargs(x="n', system('echo malicious',intern=T),'") has me hoping for an alternative.
checkargs <- function(...) {
args<-list(...)
for(var in names(args))
checkmate::qassert(get(var,envir=parent.frame()),args[[var]])
# scary string interpolation alternative
#eval(parse(text=paste0("qassert(",var,",'",args[[var]], "')")),parent.frame())
}
test_checkargs <- function(x, y) {checkargs(x='b',y='n'); print(y)}
# checkargs is working!
test_checkargs(T, 1)
# [1] 1
# but the error message isn't helpful.
test_checkargs(1, 1)
# Error in checkargs(x = "b", y = "n") :
# Assertion on 'get(var, envir = parent.frame())' failed. Must be of class 'logical', not 'double'.
#
# want:
# Assertion on 'x' failed. ...
substitute() with as.name seems to do the trick. This still uses eval but without string interpolation.
eval(substitute(
qassert(x,spec),
list(x=as.name(var),
spec=args[[var]])),
envir=parent.frame())
During my free time R studying, I read this article on usage of return(). In there, I came across a function, of which one element's meaning escapes my technical background, please see below:
bench_nor2 <- function(x,repeats) { system.time(rep(
# without explicit return
(function(x)vector(length=x,mode="numeric"))(x),repeats)) }
I've played with the codes of the article, but the logic behind this tiny (x) (specifically, it's 2nd occurrence) in the 3rd line is unclear to me.
It's an anonymous function. If we unwrap the code
bench_nor2 <- function(x,repeats) { system.time(rep(
# without explicit return
(function(x)
vector(length=x,mode="numeric")
)(x),
repeats)) }
we can see that within the rep( ... ) call, the first argument is
(function(x)vector(length=x,mode="numeric"))(x)
Now, this is a curious way of putting it. But what you get is that function(x) vector(...) defines a one-liner function (which calls vector to create a numeric vector of length x). Wrapped in parenthesis (function(x) ...) returns the function, and then with (function(x) ...)(x) calls the anonymous function with argument x.
You would get the same result from:
my_vector <- function(y) vector(length=y, mode="numeric")
bench_nor2 <- function(x, repeats) {system.time(rep(my_vector(x), repeats))}
I have an example function below that reads in a date as a string and returns it as a date object. If it reads a string that it cannot convert to a date, it returns an error.
testFunction <- function (date_in) {
return(as.Date(date_in))
}
testFunction("2010-04-06") # this works fine
testFunction("foo") # this returns an error
Now, I want to use lapply and apply this function over a list of dates:
dates1 = c("2010-04-06", "2010-04-07", "2010-04-08")
lapply(dates1, testFunction) # this works fine
But if I want to apply the function over a list when one string in the middle of two good dates returns an error, what is the best way to deal with this?
dates2 = c("2010-04-06", "foo", "2010-04-08")
lapply(dates2, testFunction)
I presume that I want a try catch in there, but is there a way to catch the error for the "foo" string whilst asking lapply to continue and read the third date?
Use a tryCatch expression around the function that can throw the error message:
testFunction <- function (date_in) {
return(tryCatch(as.Date(date_in), error=function(e) NULL))
}
The nice thing about the tryCatch function is that you can decide what to do in the case of an error (in this case, return NULL).
> lapply(dates2, testFunction)
[[1]]
[1] "2010-04-06"
[[2]]
NULL
[[3]]
[1] "2010-04-08"
One could try to keep it simple rather than to make it complicated:
Use the vectorised date parsing
R> as.Date( c("2010-04-06", "foo", "2010-04-08") )
[1] "2010-04-06" NA "2010-04-08"
You can trivially wrap na.omit() or whatever around it. Or find the index of NAs and extract accordingly from the initial vector, or use the complement of the NAs to find the parsed dates, or, or, or. It is all here already.
You can make your testFunction() do something. Use the test there -- if the returned (parsed) date is NA, do something.
Add a tryCatch() block or a try() to your date parsing.
The whole things is a little odd as you go from a one-type data structure (vector of chars) to something else, but you can't easily mix types unless you keep them in a list type. So maybe you need to rethink this.
You can also accomplish this kind of task with the purrr helper functions map and possibly. For example
library(purrr)
map(dates2, possibly(testFunction, NA))
Here possibly will return NA (or whatever value you specified if an error occurs.
Assuming the testFunction() is not trivial and/or that one cannot alter it, it can be wrapped in a function of your own, with a tryCatch() block. For example:
> FaultTolerantTestFunction <- function(date_in) {
+ tryCatch({ret <- testFunction(date_in);}, error = function(e) {ret <<- NA});
+ ret
+ }
> FaultTolerantTestFunction('bozo')
[1] NA
> FaultTolerantTestFunction('2010-03-21')
[1] "2010-03-21"
I see there is another related question, but the answer isnt what I am looking for. I want a function that can be assigned to an object, but still will print the output even when assigned, but not double print it.
In this case:
fun <- function(x) {
print(x+1)
x+1
}
a <- fun(3)
In this case, it would both save to a, and it would print to console, which is what I want.
But in this case:
fun(3)
It would print to the console twice. Is there a way to get the desired result from case 1, without double printing on case 2?
Assuming that you still want your function to return the 'x+1' value, you could just wrap it in the invisible function:
fun <- function(x) {
print(x+1)
invisible(x+1)
}
> fun(3)
[1] 4
> a = fun(3)
[1] 4
> a
[1] 4
This will only print it out once, while still retaining the 'x+1' value.
You can accomplish this same behavior with any function in R that visibly returns an object by wrapping it in parentheses.
fun <- function(x) {
x+1
}
> (fun(3))
[1] 4
> (a = fun(3))
[1] 4
> a
[1] 4
Or, equivalently, you may simply call print on your assignment.
> print(fun(3))
[1] 4
I'm not sure rolling this functionality into a function has any benefits over using the existing print method outside of a function.
R functions shouldn't have unasked for "side effects". This isn't a rule, but a strong recommendation. As evidence for it being good practice, there are plenty of questions on SO like this one where a poorly behaved function prints output using print or cat that the end user struggles to disable.
Based on this, I would strongly encourage you to either use message() rather than print() or to add an argument that can disable the printing. message() is the "right" way print to the console during execution, but it won't format the result nicely depending on the data structure.
Thus, if your function expects simple outputs then I would recommend doing it like this:
fun <- function(x) {
result = x + 1
message(result)
invisible(result)
}
If it might have more complicated output, you could try something like this (demoing on mtcars):
fun <- function(x) {
result = head(mtcars)
sapply(capture.output(print(result)), message)
invisible(result)
}
Messages can easily be suppressed by wrapping the call in suppressMessages(), and message = F is a handy argument for knitr code chunks to say "ignore the messages".
The other option is to add an argument
fun <- function(x, quietly = FALSE) {
result = x + 1
if (!quietly) print(result)
invisible(result)
}
And I'd also think long and hard about whether this strange behavior is really necessary. Usually, having functions that behave as expected is better than having special cases that throw expectations.
I did a test with nested return function in R, but without success. I came from Mathematica, where this code works well. Here is a toy code:
fstop <- function(x){
if(x>0) return(return("Positive Number"))
}
f <- function(x){
fstop(x)
"Negative or Zero Number"
}
If I evaluate f(1), I get:
[1] "Negative or Zero Number"
When I expected just:
[1] "Positive Number"
The question is: there is some non-standard evaluation I can do in fstop, so I can have just fstop result, without change f function?
PS: I know I can put the if direct inside f, but in my real case the structure is not so simple, and this structure would make my code simpler.
Going to stick my neck out and say...
No.
Making a function return not to its caller but to its caller's caller would involve changing its execution context. This is how things like return and other control-flow things are implemented in the source. See:
https://github.com/wch/r-source/blob/trunk/src/main/context.c
Now, I don't think R level code has access to execution contexts like this. Maybe you could write some C level code that could do it, but its not clear. You could always write a do_return_return function in the style of do_return in eval.c and build a custom version of R... Its not worth it.
So the answer is most likely "no".
I think Spacedman is right, but if you're willing to evaluate your expressions in a wrapper, then it is possible by leveraging the tryCatch mechanism to break out of the evaluation stack.
First, we need to define a special RETURN function:
RETURN <- function(x) {
cond <- simpleCondition("") # dummy message required
class(cond) <- c("specialReturn", class(cond))
attr(cond, "value") <- x
signalCondition(cond)
}
Then we re-write your functions to use our new RETURN:
f <- function(x) {
fstop(x)
"Negative or Zero"
}
fstop <- function(x) if(x > 0) RETURN("Positive Number") # Note `RETURN` not `return`
Finally, we need the wrapper function (wsr here stands for "with special return") to evaluate our expressions:
wsr <- function(x) {
tryCatch(
eval(substitute(x), envir=parent.frame()),
specialReturn=function(e) attr(e, "value")
) }
Then:
wsr(f(-5))
# [1] "Negative or Zero"
wsr(f(5))
# [1] "Positive Number"
Obviously this is a little hacky, but in day to day use would be not much different than evaluating expressions in with or calling code with source. One shortcoming is this will always return to the level you call wsr from.