I see you're trying to apply non-standard argument evaluation using substitute()
to allow specifying the target list component using an unquoted symbol as the second argument of foo()
. Here's how to do that:
foo <- function(lst,name.arg) {
name.sym <- substitute(name.arg);
if (typeof(name.sym) != 'symbol') stop('name must be a symbol.');
name.str <- as.character(name.sym);
lst[[name.str]] <- as.factor(lst[[name.str]]);
lst;
};
lst <- list(CLICK_DT=c(as.Date('2015-07-01'),as.Date('2015-07-02')),CLICK=c(111,123));
lst;
## $CLICK_DT
## [1] "2015-07-01" "2015-07-02"
##
## $CLICK
## [1] 111 123
##
sapply(lst,class);
## CLICK_DT CLICK
## "Date" "numeric"
lst <- foo(foo(lst,CLICK_DT),CLICK);
lst;
## $CLICK_DT
## [1] 2015-07-01 2015-07-02
## Levels: 2015-07-01 2015-07-02
##
## $CLICK
## [1] 111 123
## Levels: 111 123
##
sapply(lst,class);
## CLICK_DT CLICK
## "factor" "factor"
Couple of additional points: You're misusing the word "attribute". In R, "attribute" is a well-defined term that refers to a secondary data object that is attached to another (primary) data object. You can read/write the attributes of an object using attr()
and attributes()
. The word you should be using here is "component", since we're talking about list components. You can also use the word "element", since lists are viewed as a kind of vector, and are even referred to as "generic vectors" in the R source.
Secondly, the dollar operator is actually a function. When you use substitute()
to access the parse tree of an expression, if the expression involves the dollar operator, then the type of the return value will be 'language'
(with class 'call'
or '{'
if surrounded by a braced block), rather than 'symbol'
(class 'name'
). This is also true of normal function calls, for example typeof(substitute(sum(1,2)))
also returns type 'language'
(and also has class 'call'
).
There are different ways your requirement could be implemented. You could support a literal string, or a symbol (as I showed), or even apply some kind of sophisticated analysis of the parse tree of the argument, such as accepting a dollar call and extracting from the resulting parse tree the RHS, and using that symbol as the component name. You could even through type detection of the argument's parse tree support some or all of these interfaces with a single function definition, although that would add complexity. I don't think that would be worth it; the way I wrote foo()
above I think is the best design, since the implementation is simple, but it also provides maximum convenience for the caller, since they can specify the target list component using an unquoted symbol.
See my answer at What is "{" class in R? for more information on R parse trees.