Help on a Display function
William Dunlap <wdunlap <at> tibco.com> writes:
But it fails on this:
> my_names <- c("Bill", "William")
> display(rev(my_names))
rev(my_names) = Error in cat(list(...), file, sep, fill, labels,
append) :
argument 3 (type 'list') cannot be handled by 'cat'
This is because you call eval() using the environment of the
function, while ordinary argument evaluation evaluates them
in the environment of the caller. Do not use eval() directly
but use the ordinary evaluation that R does automatically.
I appreciate this extensive answer.
So I decided to use the following function, suppressing the deparsed form
if there is a tag (while I'm inclined to forbid function code as input):
display <- function (...) {
evaluatedArgs <- list(...)
n <- length(evaluatedArgs)
argTags <- names(evaluatedArgs)
deparsedArgs <- lapply(substitute(placeholderFunction(...))[-1],
function(expr) {
d <- deparse(expr)
paste(d, collapse = "\n ")
}
)
if (is.null(argTags)) argTags <- rep("", n)
namedArgs <- ifelse(argTags != "", argTags, deparsedArgs)
cat(paste(namedArgs, evaluatedArgs, sep=" = "), sep = "\n")
}
It works fine on your examples,
my_names <- c("Bill", "William")
display(x=log(10), 1+2+3, sin(1), rev(my_names),
z=(function(p){lp<-log(p);lp+lp^2/2+lp^3/6})(0.2))
# x = 2.30258509299405
# 1 + 2 + 3 = 6
# sin(1) = 0.841470984807897
# rev(my_names) = c("William", "Bill")
# z = -1.00911130949159
while there still are problems with matrices (and probably other structures):
A <- matrix(1:4, 2, 2); B=diag(4)
display(A, B)
# A = 1:4
# B = c(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1)
I guess I have to define my own output representation in these cases, based
on "lapply(evaluatedArgs, class)".
Many thanks, Hans Werner
display2 <- function (...)
{
evaluatedArgs <- list(...)
argTags <- names(evaluatedArgs)
deparsedArgs <- lapply(substitute(placeholderFunction(...))[-1],
function(expr) {
d <- deparse(expr)
paste(d, collapse = "\n ") # or d[1] or ...
})
# use if(is.null(argTags)) ... cat without argTags ... ?
cat(paste(sep = " = ", argTags, deparsedArgs, evaluatedArgs),
sep = "\n")
}
> my_names <- c("Bill", "William")
> display2(rev(my_names))
= rev(my_names) = c("William", "Bill")
> display2(strings=rev(my_names))
strings = rev(my_names) = c("William", "Bill")
> display2(x=log(10), 1+2+3,
z=(function(p){lp<-log(p);lp+lp^2/2+lp^3/6})(0.2))
x = log(10) = 2.30258509299405
= 1 + 2 + 3 = 6
z = (function(p) {
lp <- log(p)
lp + lp^2/2 + lp^3/6
})(0.2) = -1.00911130949159
My questions:
(1) Is there a better or more appropriate way to write such a
function? ---
I'm not so well versed in internal R functions such as
(de)parse(),
substitute(), or eval().
(2) What is the role of the "placeholderFunction"? I could
not find enough
information about it resp. about the whole construction.
The function
f <- function(x) substitute(func(x))
produces an object of class "call" whose first element
is the name "func" and whose subsequent elements are
the arguments in the call. The [-1] strips off the
function name. You might also do
f <- function(x) substitute((x))
which produces an object of class "(" whose first element
is the name "(" which you can strip off. "(" is easier
to misread and "(" objects must have length 2, while
call objects have any length greater than 0.
I learned about this by playing around with the output of
quote() (or parse() or substitute() or expression()). Look
at the class, length, and [[elements]] of expressions.
The following str.language might get you started. It prints
the name, class, length, and a summary of the value of each
part of an expression.
[...]
Bill Dunlap
Spotfire, TIBCO Software
wdunlap tibco.com
Thanks, Hans Werner