Partial Conundrum in purrr - r

Hi I frequently find myself using .fists = FALSE argument in purrr:partial.
So today I decided to stop repeating myself and I tried to write a partial of partial itself:
backwards_partial <- partial(partial,.first = FALSE)
This function made me nervous rather quickly, because it is ambiguous as to how .first = FALSE will be used:
as a default parameter of outputted function
as argument of calling partial that will move pre-filled arguments to the back of in outputed function
I thought I could remedy this ambiguity by writing this:
backwards_partial <- lift_ld(lift_dl(partial),list(.first = FALSE))
But this failed and it does not seem elegant.
So my question is...
Is there a correct way(best practice, community standard) that I'm missing here?
If so what is it?
Otherwise how would you solve this problem?
EDIT:
I should mention my use case for having backwards_partial.
I am looking to pre-fill arguments of multiple functions that I will pass into compose which will pass results of past function into first argument, hence .fists = FALSE ensures that we are not overwriting pre-filled arguments.

Here's a way:
# copy function
backwards_partial <- purrr::partial
# change formals
formals(backwards_partial)[5] <- alist(.first = FALSE)
Let's test it:
partial(head,2)(1:5)
# Error in head.default(2, ...) : length(n) == 1L is not TRUE
partial(head,2,.first = FALSE)(1:5)
# [1] 1 2
backwards_partial(head,2)(1:5)
# [1] 1 2

Related

subvert external function's `deparse(substitute())` without `eval`

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())

How do I continue running the function when errors happen? [duplicate]

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"

'=' vs. '<-' as a function argument in R

I am a beginner so I'd appreciate any thoughts, and I understand that this question might be too basic for some of you.
Also, this question is not about the difference between <- and =, but about the way they get evaluated when they are part of the function argument. I read this thread, Assignment operators in R: '=' and '<-' and several others, but I couldn't understand the difference.
Here's the first line of code:
My objective is to get rid of variables in the environment. From reading the above thread, I would believe that <- would exist in the user workspace, so there shouldn't be any issue with deleting all variables.
Here is my code and two questions:
Question 1
First off, this code doesn't work.
rm(ls()) #throws an error
I believe this happens because ls() returns a character vector, and rm() expects an object name. Am I correct? If so, I would appreciate if someone could guide me how to get object names from character array.
Question 2
I googled this topic and found that this code below deletes all variables.
rm(list = ls())
While this does help me, I am unsure why = is used instead of <-. If I run the following code, I get an error Error in rm(list <- ls()) : ... must contain names or character strings
rm(list <- ls())
Why is this? Can someone please guide me? I'd appreciate any help/guidance.
I read this thread, Assignment operators in R: '=' and '<-' and several others, but I couldn't understand the difference.
No wonder, since the answers there are actually quite confusing, and some are outright wrong. Since that’s the case, let’s first establish the difference between them before diving into your actual question (which, it turns out, is mostly unrelated):
<- is an assignment operator
In R, <- is an operator that performs assignment from right to left, in the current scope. That’s it.
= is either an assignment operator or a distinct syntactic token
=, by contrast, has several meanings: its semantics change depending on the syntactic context it is used in:
If = is used inside a parameter list, immediately to the right of a parameter name, then its meaning is: “associate the value on the right with the parameter name on the left”.
Otherwise (i.e. in all other situations), = is also an operator, and by default has the same meaning as <-: i.e. it performs assignment in the current scope.
As a consequence of this, the operators <- and = can be used interchangeably1. However, = has an additional syntactic role in an argument list of a function definition or a function call. In this context it’s not an operator and cannot be replaced by <-.
So all these statements are equivalent:
x <- 1
x = 1
x[5] <- 1
x[5] = 1
(x <- 1)
(x = 1)
f((x <- 5))
f((x = 5))
Note the extra parentheses in the last example: if we omitted these, then f(x = 5) would be interpreted as a parameter association rather than an assignment.
With that out of the way, let’s turn to your first question:
When calling rm(ls()), you are passing ls() to rm as the ... parameter. Ronak’s answer explains this in more detail.
Your second question should be answered by my explanation above: <- and = behave differently in this context because the syntactic usage dictates that rm(list = ls()) associates ls() with the named parameter list, whereas <- is (as always) an assignment operator. The result of that assignment is then once again passed as the ... parameter.
1 Unless somebody changed their meaning: operators, like all other functions in R, can be overwritten with new definitions.
To expand on my comment slightly, consider this example:
> foo <- function(a,b) b+1
> foo(1,b <- 2) # Works
[1] 3
> ls()
[1] "b" "foo"
> foo(b <- 3) # Doesn't work
Error in foo(b <- 3) : argument "b" is missing, with no default
The ... argument has some special stuff going on that restricts things a little further in the OP's case, but this illustrates the issue with how R is parsing the function arguments.
Specifically, when R looks for named arguments, it looks specifically for arg = val, with an equals sign. Otherwise, it is parsing the arguments positionally. So when you omit the first argument, a, and just do b <- 1, it thinks the expression b <- 1 is what you are passing for the argument a.
If you check ?rm
rm(..., list = character(),pos = -1,envir = as.environment(pos), inherits = FALSE)
where ,
... - the objects to be removed, as names (unquoted) or character strings (quoted).
and
list - a character vector naming objects to be removed.
So, if you do
a <- 5
and then
rm(a)
it will remove the a from the global environment.
Further , if there are multiple objects you want to remove,
a <- 5
b <- 10
rm(a, b)
This can also be written as
rm(... = a, b)
where we are specifying that the ... part in syntax takes the arguments a and b
Similarly, when we want to specify the list part of the syntax, it has to be given by
rm(list = ls())
doing list <- ls() will store all the variables from ls() in the variable named list
list <- ls()
list
#[1] "a" "b" "list"
I hope this is helpful.

R: Testing function in interactive session

I am not sure if it is possible, but I would like to be able to grab the default argument values of a function and test them and the code within my functions without having to remove the commas (this is especially useful in the case when there are many arguments).
In effect, I want to be able to have commas when sending arguments into the function but not have those commas if I copy and paste the arguments and run them by themselves.
For example:
foo=function(
x=1,
y=2,
z=3
) {
bar(x,y,z)
}
Now to test pieces of the function outside of the code block, copy and paste
x=1,
y=2,
z=3
bar(x,y,z)
But this gives an error because there is a comma after x=1
Perhaps I am not asking the right question. If this is strange, what is the preferred method for debugging functions?
Please note, just posted nearly identical question in Julia.
If you want to programmatically get at the arguments of a function and their default values, you can use formals:
fxn = function(a, b, d = 2) {}
formals(fxn)
# $a
#
#
# $b
#
#
# $d
# [1] 2
I suppose if you wanted to store the default value of every argument to your function into a variable of that name (which is what you're asking about in the OP), then you could do this with a for loop:
info <- formals(fxn)
for (varname in names(info)) {
assign(varname, info[[varname]])
}
a
# Error: argument "a" is missing, with no default
b
# Error: argument "b" is missing, with no default
d
# [1] 2
So for arguments without default values, you'll need to provide a value after running this code (as you would expect). For arguments with defaults, they'll now be set.

How should one implement "is.error()" for R, to identify and parse errors?

I am trying to test if objects are the results of errors. The use case primarily arises via a foreach() loop that produces an error (although, for testing, it seems enough to just assign a simpleError() to a variable), and I'm puzzled about how to identify when that has occurred: how can I test that a given object is, in fact, an error? Once I've determined that it is an error, what else can I extract, besides a message? Perhaps I'm missing something about R's error handling facilities, as it seems necessary to write an error object testing function de novo.
Here are two examples, one using foreach, with the .errorhandling argument set to pass. I have begun to use that as the default for large scale or unattended processing, in the event of an anomaly in a slice of data. Such anomalies are rare, and not worth crashing the entire for loop (especially if that anomaly occurs at the end, which appears to be the default behavior of my murphysListSortingAlgorithm() ;-)). Instead, post hoc detection is desired.
library(foreach)
library(doMC)
registerDoMC(2)
results = foreach(ix = 1:10, .errorhandling = "pass") %dopar%{
if(ix == 6){
stop("Perfect")
}
if(ix == 7){
stop("LuckyPrime")
} else {
return(ix)
}
}
For simplicity, here is a very simple error (by definition):
a = simpleError("SNAFU")
While there does not seem to be a command like is.error(), and commands like typeof() and mode() seem to be pointless, the best I've found is to use class() or attributes(), which give attributes that are indicative of an error. How can I use these in a manner guaranteed to determine that I've got an error and to fully process that error? For instance a$message returns SNAFU, but a$call is NULL. Should I expect to be able to extract anything useful from, say, res[[6]]$call?
Note 1: In case one doesn't have multicore functionality to reproduce the first example, I should point out that results[[6]] isn't the same as simpleError("Perfect"):
> b = simpleError("Perfect")
> identical(results[[6]], b)
[1] FALSE
> results[[6]]
<simpleError in eval(expr, envir, enclos): Perfect>
> b
<simpleError: Perfect>
This demonstrates why I can't (very naively) test if the list element is a vanilla simpleError.
Note 2. I am aware of try and tryCatch, and use these in some contexts. However, I'm not entirely sure how I can use them to post-process the output of, say, a foreach loop. For instance, the results object in the first example: it does not appear to me to make sense to process its elements with a tryCatch wrapper. For the RHS of the operation, i.e. the foreach() loop, I'm not sure that tryCatch will do what I intend, either. I can use it to catch an error, but I suppose I need to get the message and insert the processing at that point. I see two issues: every loop would need to be wrapped with a tryCatch(), negating part of the .errorhandling argument, and I remain unable to later post-process the results object. If that's the only way to do this processing, then it's the solution, but that implies that errors can't be identified and processed in a similar way to many other R objects, such as matrices, vectors, data frames, etc.
Update 1. I've added an additional stop trigger in the foreach loop, to give two different messages to identify and parse, in case this is helpful.
Update 2. I'm selecting Richie Cotton's answer. It seems to be the most complete explanation of what I should look for, though a complete implementation requires several other bits of code (and a recent version of R). Most importantly, he points out that there are 2 types of errors we need to keep in mind, which is especially important in being thorough. See also the comments and answers by others in order to fully develop your own is.error() test function; the answer I've given can be a useful start when looking for errors in a list of results, and the code by Richie is a good starting point for the test functions.
The only two types of errors that you are likely to see in the wild are simpleErrors like you get here, and try-errors that are the result of wrapping some exception throwing code in a call to try. It is possible for someone to create their own error class, though these are rare and should be based upon one of those two classes. In fact (since R2.14.0) try-errors contain a simpleError:
e <- try(stop("throwing a try-error"))
attr(e, "condition")
To detect a simpleError is straightforward.
is_simple_error <- function(x) inherits(x, "simpleError")
The equivalent for try catch errors is
is_try_error <- function(x) inherits(x, "try-error")
So here, you can inspect the results for problems by applying this to your list of results.
the_fails <- sapply(results, is_simple_error)
Likewise, returning the message and call are one-liners. For convenience, I've converted the call to a character string, but you might not want that.
get_simple_error_message <- function(e) e$message
get_simple_error_call <- function(e) deparse(e$call)
sapply(results[the_fails], get_simple_error_message)
sapply(results[the_fails], get_simple_error_call)
From ?simpleError:
Conditions are objects inheriting from the abstract class condition.
Errors and warnings are objects inheriting from the abstract
subclasses error and warning. The class simpleError is the class used
by stop and all internal error signals. Similarly, simpleWarning is
used by warning, and simpleMessage is used by message. The
constructors by the same names take a string describing the condition
as argument and an optional call. The functions conditionMessage and
conditionCall are generic functions that return the message and call
of a condition.
So class(a) returns:
[1] "simpleError" "error" "condition"
So a simple function:
is.condition <- function(x) {
require(taRifx)
last(class(x))=="condition"
}
As #flodel notes, replacing the function body with inherits(x,"condition") is more robust.
Using #flodel's suggestion about inherits(), which gets at the abstract class inheritance mentioned by #gsk3, here's my current solution:
is.error.element <- function(x){
testError <- inherits(x, "error")
if(testError == TRUE){
testSimple <- inherits(x, "simpleError")
errMsg <- x$message
} else {
testSimple <- FALSE
errMsg <- NA
}
return(data.frame(testError, testSimple, errMsg, stringsAsFactors = FALSE))
}
is.error <- function(testObject){
quickTest <- is.error.element(testObject)
if(quickTest$testError == TRUE){
return(quickTest)
} else {
return(lapply(testObject, is.error.element))
}
}
Here are results, made pretty via ldply for the results list:
> ldply(is.error(results))
testError testSimple errMsg
1 FALSE FALSE <NA>
2 FALSE FALSE <NA>
3 FALSE FALSE <NA>
4 FALSE FALSE <NA>
5 FALSE FALSE <NA>
6 TRUE TRUE Perfect
7 TRUE TRUE LuckyPrime
8 FALSE FALSE <NA>
9 FALSE FALSE <NA>
10 FALSE FALSE <NA>
> is.error(a)
testError testSimple errMsg
1 TRUE TRUE SNAFU
This still seems rough to me, not least because I haven't extracted a meaningful call value, and the outer function, isError(), might not do well on other structures. I suspect that this could be improved with sapply or another member of the *apply or *ply (plyr) families.
I use try and catch as described in this question:
How do I save warnings and errors as output from a function?
The idea is that each item in the loop returns a list with three elements: the return value, any warnings, and any errors. The result is a list of lists that can then be queried to find out not only the values from each item in the loop, but which items in the loop had warnings or errors.
In this example, I would do something like this:
library(foreach)
library(doMC)
registerDoMC(2)
results = foreach(ix = 1:10, .errorhandling = "pass") %dopar%{
catchToList({
if(ix == 6){
stop("Perfect")
}
if(ix == 7){
stop("LuckyPrime")
} else {
ix
}
})
}
Then I would process the results like this
> ok <- sapply(results, function(x) is.null(x$error))
> which(!ok)
[1] 6 7
> sapply(results[!ok], function(x) x$error)
[1] "Perfect" "LuckyPrime"
> sapply(results[ok], function(x) x$value)
[1] 1 2 3 4 5 8 9 10
It would be fairly straightforward to give the result from catchToList a class and overload some accessing functions to make the above syntax easier, but I haven't found a real need for that yet.

Resources