Methods for recursive concatenations on user defined classes in R? - r

All the concatenation functions in R can be rewritten as recursive functions. For instance, I could use c as a binary operator and I could define a new concat function as
concat <- function(...) {
Reduce(c, ...)
}
and concat would function as c actually functions in R base.
R syntactically uses many such functions, for instance c for vectors and lists, cbind for arrays, data.frames and matrices. When defining new object classes, it makes sense to create a method for combining them using a function which takes ... as an argument.
I know R can match methods to objects when they are the first object in the argument list, but what if I define a method like
concat <- function(...) {
UseMethod('concat')
}
concat.numeric <- function(...) {
c(...)
}
concat.character <- function(...) {
c(...)
}
myCon <- function(charPart, numPart) {
out <- list(charPart=charPart, numPart=numPart)
class(out) <- "myClass"
out
}
concat.myClass <- function(...) {
myCon(sapply(..., `[[`, 'charPart'), sapply(..., `[[`, 'numPart'))
}
> concat(4, 6, 'a')
"4" "6" "a"
> myObj1 <- myCon('a', 1)
> myObj2 <- myCon('b', 2)
> concat(myObj1, myObj2)
Error in get(as.character(FUN), mode = "function", envir = envir) :
object 'p' of mode 'function' was not found
At what point does R identify the types of arguments supplied to concat? How can I convince R to attempt to cast arguments to concat up to my specific object class?

You're not quite passing what you think to sapply you need to put it in list(...) so sapply can iterate through the elements rather than parsing them as extra arguments in the wrong place.
concat.myClass <- function(...)
{
myCon(sapply(list(...), `[[`, 'charPart'), sapply(list(...), `[[`, 'numPart'))
}
> myObj1
$charPart
[1] "a"
$numPart
[1] 1
attr(,"class")
[1] "myClass"
> myObj2
$charPart
[1] "b"
$numPart
[1] 2
attr(,"class")
[1] "myClass"
this then gives:
> concat(myObj1, myObj2)
$charPart
[1] "a" "b"
$numPart
[1] 1 2
attr(,"class")
[1] "myClass"
.. which I presume is what you want???

Related

R functions, access to parameter names

I have the following code:
fn <- 'George'
mn <- 'Walker'
ln <- 'Bush'
f <- function(...) { print(list(...)) }
When I call it, it produces the following output:
f(fn,mn,ln)
[[1]]
[1] "George"
[[2]]
[1] "Walker"
[[3]]
[1] "Bush"
Suppose I wanted something similar to this (note the parameter names):
fn:George
mn:Walker
ln:Bush
Question: I know how to get the VALUES of the arguments inside a function. How do I get the NAMES of the arguments inside the function?
Thanks, CC.
You may use
f <- function(...) {
nm1 <- as.list(match.call()[-1])
val <- list(...)
cat(paste(nm1, val, sep=":", collapse="\n"),'\n') }
f(fn,mn,ln)
#fn:George
#mn:Walker
#ln:Bush

Loop over list of functions, and return function name as character

In R, I have a list of functions (strategies for a simulation). For example:
a <- function(x){
return(x)
}
b <- function(y){
return(y)
}
funclist <- list(a,b)
I'd like to write some code that returns the name of each function. Normally, for functions I would use:
as.character(substitute(a))
But this does not work for the list, as it just would return the list name (as expected). I then tried lapply:
> lapply(X = funclist,FUN = substitute)
Error in lapply(X = funclist, FUN = substitute) :
'...' used in an incorrect context
But get the above error.
Ideally I would get (lapply solution):
[[1]]
[1] "a"
[[2]]
[1] "b"
or even (sapply solution):
[1] "a" "b"
After you do
funclist <- list(a,b)
The parameters a and b are evaluated and the functions they point to are returned. There is no way to get back to the original names. (The substitute() "trick" works on parameters passed to functions as promises. It will not work on evaluated called without additional escaping.)
If you want to retain names, it's best to use a named list. You can do
funclist <- list(a=a,a=b)
or
funclist <- setNames(list(a,b), c("a","b"))
or even use mget() here
funclist <- mget(c("a","b"))
All these methods will returned a named list and you can use
names(funclist)
# [1] "a" "b"
to get the names

Get list of datatypes with S3 generic function

I try to write a function where I can throw in a abitrary number of objects and get a list of the datatypes of that objects. This is a personal task to learn S3 Generics.
What I have done so far is:
myTypes <- function(x, ...) {
dots <- list(...)
return (as.list(apply(dots, 1, myType)))
}
myType <- function(x){
UseMethod("myType")
}
myType.numeric <- function(x){
if(is.numeric(x)) "Type: numberic"
}
myType.data.frame <- function(x){
if(is.data.frame(x)) "Type: dataframe"
}
The error occurs e.g. when I call
x <- 1
y <- 3
myTypes(x,y)
I always get the error: "Error in apply(dots, 1, myType) : dim(X) must have a positive length" and I am not sure what is wrong. Could anyone help me here? Since I am totally new to R I maybe doing something basically wrong.
The first argument of apply must be a matrix-like object (i.e., a matrix, array or data.frame). Otherwise you get this error:
apply(1, 1, mean)
#Error in apply(1, 1, mean) : dim(X) must have a positive length
You are passing a list to apply, which can't work because you tell apply to apply the function along the first dimension and a list doesn't have dimensions.
You probably want to use lapply and not apply:
myTypes <- function( ...) {
dots <- list(...)
lapply(dots, myType)
}
x <- 1
y <- 3
myTypes(x,y)
#[[1]]
#[1] "Type: numberic"
#
#[[2]]
#[1] "Type: numberic"
Of course, it seems more useful, to simply return the class:
myTypes <- function(...) {
dots <- list(...)
lapply(dots, class)
}
myTypes(x,y)
#[[1]]
#[1] "numeric"
#
#[[2]]
#[1] "numeric"
Btw., if you use S3 method dispatch, you don't have to test the class inside the method because a method is only dispatched if the object has the corresponding class.

Suppress output from attr() in function result

In the source code for data.frame, the last three lines of code set the attributes and return the result.
...
attr(value, "row.names") <- row.names
attr(value, "class") <- "data.frame"
value
}
In a function I wrote, the result is a named list created by lapply. Before I set any attributes in the function body, result is as follows.
> x <- data.frame(a = 1:5, b = letters[1:5])
> (g <- grep.dataframe("a|c", x))
# ...
# $b
# value row
# 1 a 1
# 2 c 3
> attributes(g) # I want "list" in here...
# $names
# [1] "a" "b"
I'd like "class" to be included in the attributes list, so I add attr(res, "class") <- "list" (res is the final result) just before res. "class" now shows up in the attributes list. However,it also prints out with the result of the function, which I don't want. I tried wrapping it with invisible, but that didn't work.
Why do the manually assigned attributes print with the function result, but are suppressed in a new data frame I create?
> (h <- grep.dataframe("a|c", x))
# ...
# $b
# value row
# 1 a 1
# 2 c 3
# attr(,"class") # ...This prints with the result. I don't want that.
# [1] "list"
> attributes(h) # ...But I want these attributes
# $names
# [1] "a" "b"
# $class
# [1] "list"
The ?class documentation offers some pointers:
Many R objects have a class attribute, a character vector giving the names of the classes from which the object inherits. If the object does not have a class attribute, it has an implicit class, "matrix", "array" or the result of mode(x) (except that integer vectors have implicit class "integer"). (Functions oldClass and oldClass<- get and set the attribute, which can also be done directly.)
When a generic function fun is applied to an object with class attribute c("first", "second"), the system searches for a function called fun.first and, if it finds it, applies it to the object. If no such function is found, a function called fun.second is tried. If no class name produces a suitable function, the function fun.default is used (if it exists). If there is no class attribute, the implicit class is tried, then the default method.
From that and running a few simple tests, I gather that:
a list is one of these implicit classes: see attributes(list(1)), typeof(list(1))
when print is called on a list, it is using print.default
print.default prints the attributes of an object
So you could define a print.list that will handle your special case:
print.list <- function(x, ...) {
if (is.list(x)) attr(x, "class") <- NULL
print.default(x, ...)
}
res <- list(1)
attr(res, "class") <- "list"
res
# [[1]]
# [1] 1
attributes(res)
# $class
# [1] "list"

binding a function to a list

Where am I missing something?
FUN<-list()
make.FUN<-function(i) function(n) i+n
for (i in 1:3) FUN[[i]]<-make.FUN(i)
FUN[[1]](1)
If I check FUN assignment I get a reference to a nested function (as expected):
> FUN
[[1]]
function (n)
i + n
<environment: 0x03adfad0>
[[2]]
function (n)
i + n
<environment: 0x03ae0834>
[[3]]
function (n)
i + n
<environment: 0x03ae0604>
>
Problem is that if I check:
> FUN[[1]](1)
[1] 4
>
when I expect 2! (clearly it is overwriting the last value)
On the other hand, if I manually assign for each element of the list:
FUN[[1]]<-make.FUN(1)
FUN[[2]]<-make.FUN(2)
FUN[[3]]<-make.FUN(3)
I get the correct answer:
> FUN[[1]](1)
[1] 2
> FUN[[2]](3)
[1] 5
>
I could workaround using do.call, but I can't realize what the interpreter is assuming in the first loop, or why is do.call mandatory in this case.
When I try:
FUN<-list()
make.FUN<-function(i) function(n) i+n
for (i in 1:3) FUN[[i]]<-do.call('make.FUN',list(i))
I get (as expected):
> FUN[[1]](2)
[1] 3
Any clue? (it only happens when using lists)
Your question is almost a copy-paste of the force example from the doc. You need to do:
FUN <- list()
make.FUN <- function(i) { force(i); function(n) i+n }
for (i in 1:3) FUN[[i]] <- make.FUN(i)
FUN[[1]](1)
# [1] 2
Relevant details from ?force:
force forces the evaluation of a formal argument. This can be useful if the argument will be captured in a closure by the lexical scoping rules and will later be altered by an explicit assignment or an implicit assignment in a loop or an apply function.

Resources