From: Bill Dunlap <bill_at_insightful.com>

Date: Fri, 26 Oct 2007 12:46:25 -0700 (PDT)

or

and ran it over all our source code. Out of curiousity I also ran it over the current R source and an out-of-date copy of the package source code from CRAN and that is where I ran across the problem in polr() (and lots of instances in packages, although they seemed to be clustered).

}

This code works in Splus and R. E.g.,

If I get around the "'object' must be a list' problem by wrapping the input in a list then I run into the evalution problem

}

}

> changeLogCalls(function(x)log(x,2)/log(x)) function(x)

logb(x, 2)/log(x)

Bill Dunlap

Insightful Corporation

bill at insightful dot com

R-devel_at_r-project.org mailing list

https://stat.ethz.ch/mailman/listinfo/r-devel Received on Fri 26 Oct 2007 - 19:52:26 GMT

Date: Fri, 26 Oct 2007 12:46:25 -0700 (PDT)

On Fri, 26 Oct 2007, Martin Maechler wrote:

> Apropos Bill Dunlap's note: Do newer versions of S-plus warn?

*> At least up to 6.2.2, I'm pretty sure no S version has warned
**> about
**> X <- c(0.1, pi)
**> all(X) > 0.5
*

Hi Martin,

No, it doesn't warn. We had a user who ran into a bug in another function that came from this sort of thing so I wrote some code that examined parse trees for expresions of the form

<comparison operator>

<call to any or all> <anything>

or

<comparison operator>

<anything> <call to any or all>

and ran it over all our source code. Out of curiousity I also ran it over the current R source and an out-of-date copy of the package source code from CRAN and that is where I ran across the problem in polr() (and lots of instances in packages, although they seemed to be clustered).

Now I have a question/complaint about doing this. In Splus I looked for this pattern with the following code

isComparisonOfAnyOrAll <- function(expr)

isCallTo(expr, c("<", ">", "<=", ">=", "==")) && (isCallTo(expr[[2]], c("any", "all")) || isCallTo(expr[[3]], c("any", "all")))where isCallTo is

isCallTo <- function(expr, functionName, numberArgs = NULL) {

# return TRUE if expr is a call to with one of the functions # listed in functionName. If numberArgs is non-NULL, it should # be a nonnegative integer giving the required number of arguments # in the call if(class(expr) == "call with ...") { # e.g., Quote(foo(x, ..., value = TRUE)) # This class is only in Splus if(!is.null(numberArgs)) { warning("call has ... in argument list, numberArgs will count all ... arguments as 1 argument" ) } expr <- expr[[1]] } if(length(functionName) == 1) { retval <- class(expr) == "call" && identical(expr[[1]], as.name( functionName)) && (is.null(numberArgs) || numberArgs == length(expr) - 1) } else { retval <- class(expr) == "call" && is.name(expr[[1]]) && is.element(as.character(expr[[1]]), functionName) && (is.null(numberArgs) || numberArgs == length(expr) - 1) } retval

}

This code works in Splus and R. E.g.,

> isComparisonOfAnyOrAll(Quote(any(x)<0))
** [1] TRUE
**

> isComparisonOfAnyOrAll(Quote(any(x<0)))
** [1] FALSE
**
In Splus I use

rapply(expr, classes="call",

f=function(x)if(isComparisonOfAnyOrAll(x))deparseText(x))
to rattle down an an expression tree looking for this pattern.
However's R's rapply won't let me do that because
it insists its input be a function instead of being of
recursive type. Its help file says it evaluates the arguments
to f() even if they are expressions, and that may contribute
to problems. The Splus rapply accepts any recursive type and it does not
evaluate the subtrees that it hands to f().

E.g., running the same input into R and Splus and labelling the output lines 'Splus:' and 'R :', we get RS> rapply(function(x)log(x+1), f = function(expr) if (is.name(expr)) as.character(expr)) # all.names()

Splus: [1] "log" "+" "x" R : Error in rapply(function(x) log(x + 1), f = function(expr) if (is.name(expr)) as.character(expr)) : R : 'object' must be a list

If I get around the "'object' must be a list' problem by wrapping the input in a list then I run into the evalution problem

Does R have an rapply-like function that works like Splus's?

Are the R parse tree classes sufficiently different from lists that we cannot expect the above to work?

In Splus I've used rapply quite productively to find patterns in parse trees and then change the code. E.g., to change all calls of the form

log(x, base)

to

logb(x, base)

but not change calls of the form log(x) you can do

> changeLogCalls<-function(func) {

rapply(func, classes="call", how="replace", function(expr){ if(isCallTo(expr,"log",2)) expr[[1]] <- as.name("logb") expr })

}

}

> changeLogCalls(function(x)log(x,2)/log(x)) function(x)

logb(x, 2)/log(x)

I suspect I should be looking in codetools for this sort of thing.

Bill Dunlap

Insightful Corporation

bill at insightful dot com

"All statements in this message represent the opinions of the author and do not necessarily reflect Insightful Corporation policy or position."

R-devel_at_r-project.org mailing list

https://stat.ethz.ch/mailman/listinfo/r-devel Received on Fri 26 Oct 2007 - 19:52:26 GMT

Archive maintained by Robert King, hosted by
the discipline of
statistics at the
University of Newcastle,
Australia.

Archive generated by hypermail 2.2.0, at Tue 30 Oct 2007 - 03:46:12 GMT.

*
Mailing list information is available at https://stat.ethz.ch/mailman/listinfo/r-devel.
Please read the posting
guide before posting to the list.
*