Re: [Rd] A trap for young players with the lapply() function.

2017-03-29 Thread Rolf Turner

On 29/03/17 20:32, Enrico Schumann wrote:

(inline)

On Tue, 28 Mar 2017, Rolf Turner writes:


On 28/03/17 04:21, Barry Rowlingson wrote:

On Mon, Mar 27, 2017 at 1:17 AM, Rolf Turner  wrote:


Is there any way to trap/detect the use of an optional argument called
"X" and thereby issue a more perspicuous error message?

This would be helpful to those users who, like myself, are bears of very
little brain.

Failing that (it does look impossible)


You can get the names of named arguments:

 > z = function(x,X){cos(x*X)}
 > names(formals(z))
 [1] "x" "X"


That doesn't seem to help.  I tried putting a browser inside lapply()
and looked at formals(FUN).  This gave NULL, because FUN has already
been taken to be the list argument "x" to which lapply() is being
applied.


You can get the call, without the arguments being
matched, with `sys.call`. In your call of lapply,
saying `sys.call()` before anything else would give
you


lapply(y, function(x, X) {
cos(x * X)
}, X = 2 * pi)

which would allow you to get at the argument names of
your function.

if ("X" %in% names(sys.call()[[3L]][[2L]]))
   warnings("found 'X'")

But more would be needed: you need to figure out which
argument you actually meant to be FUN. (In the above,
I simply assumed it was the second passed argument.)
That is, you would need to figure out which passed
argument is a function, which is not safe either,
since ... may also contain functions.



This idea appears to work for the particular example that I used, but it 
is not clear to me how to make it work in general.  E.g. if we define


  foo <- function(x,X){X*x}

and then do

  lapply(xxx,foo,X=2*pI)

we find that sys.call[[3]] is of length 1 and consists only of the 
*name* "foo".  One can then inspect


   formals(get(as.character(sys.call[[3]])))

and find "X" therein, on the basis of which to trigger a warning.

However I don't know how to approach distinguish the two cases, or how 
to discern if there may be other cases lurking in the bushes.


So the problem still looks insoluble to me.

cheers,

Rolf

--
Technical Editor ANZJS
Department of Statistics
University of Auckland
Phone: +64-9-373-7599 ext. 88276

__
R-devel@r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel


Re: [Rd] A trap for young players with the lapply() function.

2017-03-29 Thread Enrico Schumann
(inline)

On Tue, 28 Mar 2017, Rolf Turner writes:

> On 28/03/17 04:21, Barry Rowlingson wrote:
>> On Mon, Mar 27, 2017 at 1:17 AM, Rolf Turner  wrote:
>>>
>>> Is there any way to trap/detect the use of an optional argument called
>>> "X" and thereby issue a more perspicuous error message?
>>>
>>> This would be helpful to those users who, like myself, are bears of very
>>> little brain.
>>>
>>> Failing that (it does look impossible)
>>
>> You can get the names of named arguments:
>>
>>  > z = function(x,X){cos(x*X)}
>>  > names(formals(z))
>>  [1] "x" "X"
>
> That doesn't seem to help.  I tried putting a browser inside lapply()
> and looked at formals(FUN).  This gave NULL, because FUN has already
> been taken to be the list argument "x" to which lapply() is being
> applied.

You can get the call, without the arguments being
matched, with `sys.call`. In your call of lapply,
saying `sys.call()` before anything else would give
you


lapply(y, function(x, X) {
cos(x * X)
}, X = 2 * pi)

which would allow you to get at the argument names of
your function.

if ("X" %in% names(sys.call()[[3L]][[2L]]))
   warnings("found 'X'")

But more would be needed: you need to figure out which
argument you actually meant to be FUN. (In the above,
I simply assumed it was the second passed argument.)
That is, you would need to figure out which passed
argument is a function, which is not safe either,
since ... may also contain functions.


>>> might it not be a good idea to
>>> add a warning to the help for lapply(), to the effect that if FUN has an
>>> optional argument named "X" then passing this argument via "..." will
>>> cause this argument to be taken as the first argument to lapply() and
>>> thereby induce an error?
>>
>> Another idea might be to use purrr:map instead, which is quite happy
>> with X in your function:
>>
>>  >  xxx <- purrr::map(y,function(x,X){cos(x*X)},X=2*pi)
>>  > xxx
>> [[1]]
>> [1] 0.08419541
>>
>> [[2]]
>> [1] 0.6346404
>>
>> [[3]]
>> [1] 0.9800506
>>
>> [[4]]
>> [1] 0.8686734
>>
>> [[5]]
>> [1] -0.9220073
>>
>> But don't feed `.x` to your puing cats, or fails silently:
>>
>>  >  xxx <- purrr::map(y,function(x,.x){cos(x*.x)},.x=2*pi)
>>  > xxx
>> [[1]]
>> NULL
>>
>> But who would have a function with `.x` as an argument?
>
> Indeed.  It struck me that a possible workaround would be to change
> the name of the first argument of lapply() from "X" to ".X".  No-one
> would have a function with an argument names ".X" --- at least I
> wouldn't, so this would solve the problem for me.
>
> It seems to me that this change could be made without breaking anything.
> But perhaps I am engaging in my usual PollyAnna-ish optimism! :-)
>
> cheers,
>
> Rolf

-- 
Enrico Schumann
Lucerne, Switzerland
http://enricoschumann.net

__
R-devel@r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel


Re: [Rd] A trap for young players with the lapply() function.

2017-03-28 Thread Rolf Turner


On 29/03/17 11:03, William Dunlap wrote:


I think that the suggestion I made, in response to a posting by
Barry Rowlingson, that the first argument of lapply() be given the name of
".X" rather than just-plain-X, would be (a) effective, and (b) harmless.


It would break any call to *apply() that used X= to name the first
argument. There are currently 3020 such calls in the R code in CRAN.


Okay.  Scratch that idea.


One can avoid the problem by creating the function given as the FUN
argument when one calls lapply() and the like.  Don't give that
function arguments named "X", "FUN", "USE.NAMES", etc. and perhaps
make use of R's lexical scoping to avoid having to use many arguments
to the function.  E.g., instead of
sapply(1:5, sin)
use
sapply(1:5, function(theta) sin(theta))
or instead of
myY <- 3
sapply(1:5, atan2, y=myY)
use
myY <- 3
sapply(1:5, function(x) atan2(myY, x))


Again, all very sound advice but it does not address the problem of 
there being a trap for young players.  The advice can only be applied by 
a user only if the user is *aware* of the trap.


At this point it would appear that the problem is fundamentally 
unsolvable. :-(


cheers,

Rolf

--
Technical Editor ANZJS
Department of Statistics
University of Auckland
Phone: +64-9-373-7599 ext. 88276

__
R-devel@r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel


Re: [Rd] A trap for young players with the lapply() function.

2017-03-28 Thread William Dunlap via R-devel
>I think that the suggestion I made, in response to a posting by Barry 
>>Rowlingson, that the first argument of lapply() be given the name of ".X" 
>rather >than just-plain-X, would be (a) effective, and (b) harmless.

It would break any call to *apply() that used X= to name the first
argument.  There are currently 3020 such calls in the R code in CRAN.

One can avoid the problem by creating the function given as the FUN
argument when one calls lapply() and the like.  Don't give that
function arguments named "X", "FUN", "USE.NAMES", etc. and perhaps
make use of R's lexical scoping to avoid having to use many arguments
to the function.  E.g., instead of
sapply(1:5, sin)
use
sapply(1:5, function(theta) sin(theta))
or instead of
myY <- 3
sapply(1:5, atan2, y=myY)
use
myY <- 3
sapply(1:5, function(x) atan2(myY, x))

Bill Dunlap
TIBCO Software
wdunlap tibco.com


On Tue, Mar 28, 2017 at 2:30 PM, Rolf Turner  wrote:
> On 28/03/17 15:26, Charles C. Berry wrote:
>>
>> On Mon, 27 Mar 2017, Rolf Turner wrote:
>>
>>>
>>> From time to time I get myself into a state of bewilderment when using
>>> apply() by calling it with FUN equal to a function which has an
>>> "optional" argument named "X".
>>>
>>> E.g.
>>>
>>>xxx <- lapply(y,function(x,X){cos(x*X)},X=2*pi)
>>>
>>> which produces the error message
>>>
 Error in get(as.character(FUN), mode = "function", envir = envir) :
   object 'y' of mode 'function' was not found
>>>
>>>
>>> This of course happens because the name of the first argument of
>>> lapply() is "X" and so it takes the value of this first argument to be
>>> the supplied X (2*pi in the foregoing example) and then expects what
>>> the user has denoted by "y" to be the value of FUN, and (obviously!)
>>> it isn't.
>>>
>>
>> The lapply help page addresses this issue in `Details' :
>>
>> "it is good practice to name the first two arguments X and FUN if ... is
>> passed through: this both avoids partial matching to FUN and ensures
>> that a sensible error message is given if arguments named X or FUN are
>> passed through ..."
>>
>> So that advice suggests something like:
>>
>> xxx <- lapply( X=y, FUN=function(X,x){cos(X*x)}, x=2*pi )
>
>
>
> That is of course very sound advice, but it pre-supposes that the user is
> *aware* that there is a pitfall to be avoided.  I was hoping for something
> that would protect dweebs like myself from the pitfall given that we are too
> obtuse to be cognizant of its existence.
>
> I think that the suggestion I made, in response to a posting by Barry
> Rowlingson, that the first argument of lapply() be given the name of ".X"
> rather than just-plain-X, would be (a) effective, and (b) harmless.
>
> cheers,
>
> Rolf
>
> --
> Technical Editor ANZJS
> Department of Statistics
> University of Auckland
> Phone: +64-9-373-7599 ext. 88276
>
> __
> R-devel@r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel

__
R-devel@r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel


Re: [Rd] A trap for young players with the lapply() function.

2017-03-28 Thread Rolf Turner

On 28/03/17 15:26, Charles C. Berry wrote:

On Mon, 27 Mar 2017, Rolf Turner wrote:



From time to time I get myself into a state of bewilderment when using
apply() by calling it with FUN equal to a function which has an
"optional" argument named "X".

E.g.

   xxx <- lapply(y,function(x,X){cos(x*X)},X=2*pi)

which produces the error message


Error in get(as.character(FUN), mode = "function", envir = envir) :
  object 'y' of mode 'function' was not found


This of course happens because the name of the first argument of
lapply() is "X" and so it takes the value of this first argument to be
the supplied X (2*pi in the foregoing example) and then expects what
the user has denoted by "y" to be the value of FUN, and (obviously!)
it isn't.



The lapply help page addresses this issue in `Details' :

"it is good practice to name the first two arguments X and FUN if ... is
passed through: this both avoids partial matching to FUN and ensures
that a sensible error message is given if arguments named X or FUN are
passed through ..."

So that advice suggests something like:

xxx <- lapply( X=y, FUN=function(X,x){cos(X*x)}, x=2*pi )



That is of course very sound advice, but it pre-supposes that the user 
is *aware* that there is a pitfall to be avoided.  I was hoping for 
something that would protect dweebs like myself from the pitfall given 
that we are too obtuse to be cognizant of its existence.


I think that the suggestion I made, in response to a posting by Barry 
Rowlingson, that the first argument of lapply() be given the name of 
".X" rather than just-plain-X, would be (a) effective, and (b) harmless.


cheers,

Rolf

--
Technical Editor ANZJS
Department of Statistics
University of Auckland
Phone: +64-9-373-7599 ext. 88276

__
R-devel@r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel


Re: [Rd] A trap for young players with the lapply() function.

2017-03-27 Thread Charles C. Berry

On Mon, 27 Mar 2017, Rolf Turner wrote:



From time to time I get myself into a state of bewilderment when using
apply() by calling it with FUN equal to a function which has an "optional" 
argument named "X".


E.g.

   xxx <- lapply(y,function(x,X){cos(x*X)},X=2*pi)

which produces the error message


Error in get(as.character(FUN), mode = "function", envir = envir) :
  object 'y' of mode 'function' was not found


This of course happens because the name of the first argument of lapply() is 
"X" and so it takes the value of this first argument to be the supplied X 
(2*pi in the foregoing example) and then expects what the user has denoted by 
"y" to be the value of FUN, and (obviously!) it isn't.




The lapply help page addresses this issue in `Details' :

"it is good practice to name the first two arguments X and FUN if ... is 
passed through: this both avoids partial matching to FUN and ensures that 
a sensible error message is given if arguments named X or FUN are passed 
through ..."


So that advice suggests something like:

xxx <- lapply( X=y, FUN=function(X,x){cos(X*x)}, x=2*pi )

Best,

Chuck

__
R-devel@r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel


Re: [Rd] A trap for young players with the lapply() function.

2017-03-27 Thread Rolf Turner

On 28/03/17 04:21, Barry Rowlingson wrote:

On Mon, Mar 27, 2017 at 1:17 AM, Rolf Turner  wrote:


Is there any way to trap/detect the use of an optional argument called
"X" and thereby issue a more perspicuous error message?

This would be helpful to those users who, like myself, are bears of very
little brain.

Failing that (it does look impossible)


You can get the names of named arguments:

 > z = function(x,X){cos(x*X)}
 > names(formals(z))
 [1] "x" "X"


That doesn't seem to help.  I tried putting a browser inside lapply()
and looked at formals(FUN).  This gave NULL, because FUN has already 
been taken to be the list argument "x" to which lapply() is being applied.



might it not be a good idea to
add a warning to the help for lapply(), to the effect that if FUN has an
optional argument named "X" then passing this argument via "..." will
cause this argument to be taken as the first argument to lapply() and
thereby induce an error?


Another idea might be to use purrr:map instead, which is quite happy
with X in your function:

 >  xxx <- purrr::map(y,function(x,X){cos(x*X)},X=2*pi)
 > xxx
[[1]]
[1] 0.08419541

[[2]]
[1] 0.6346404

[[3]]
[1] 0.9800506

[[4]]
[1] 0.8686734

[[5]]
[1] -0.9220073

But don't feed `.x` to your puing cats, or fails silently:

 >  xxx <- purrr::map(y,function(x,.x){cos(x*.x)},.x=2*pi)
 > xxx
[[1]]
NULL

But who would have a function with `.x` as an argument?


Indeed.  It struck me that a possible workaround would be to change the 
name of the first argument of lapply() from "X" to ".X".  No-one would 
have a function with an argument names ".X" --- at least I wouldn't, so 
this would solve the problem for me.


It seems to me that this change could be made without breaking anything.
But perhaps I am engaging in my usual PollyAnna-ish optimism! :-)

cheers,

Rolf

--
Technical Editor ANZJS
Department of Statistics
University of Auckland
Phone: +64-9-373-7599 ext. 88276

__
R-devel@r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel


Re: [Rd] A trap for young players with the lapply() function.

2017-03-27 Thread Barry Rowlingson
On Mon, Mar 27, 2017 at 1:17 AM, Rolf Turner  wrote:
>
> Is there any way to trap/detect the use of an optional argument called
> "X" and thereby issue a more perspicuous error message?
>
> This would be helpful to those users who, like myself, are bears of very
> little brain.
>
> Failing that (it does look impossible)

You can get the names of named arguments:

 > z = function(x,X){cos(x*X)}
 > names(formals(z))
 [1] "x" "X"


> might it not be a good idea to
> add a warning to the help for lapply(), to the effect that if FUN has an
> optional argument named "X" then passing this argument via "..." will
> cause this argument to be taken as the first argument to lapply() and
> thereby induce an error?

Another idea might be to use purrr:map instead, which is quite happy
with X in your function:

 >  xxx <- purrr::map(y,function(x,X){cos(x*X)},X=2*pi)
 > xxx
[[1]]
[1] 0.08419541

[[2]]
[1] 0.6346404

[[3]]
[1] 0.9800506

[[4]]
[1] 0.8686734

[[5]]
[1] -0.9220073

But don't feed `.x` to your puing cats, or fails silently:

 >  xxx <- purrr::map(y,function(x,.x){cos(x*.x)},.x=2*pi)
 > xxx
[[1]]
NULL

But who would have a function with `.x` as an argument?


> __
> R-devel@r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel

__
R-devel@r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel


[Rd] A trap for young players with the lapply() function.

2017-03-26 Thread Rolf Turner


From time to time I get myself into a state of bewilderment when using
apply() by calling it with FUN equal to a function which has an 
"optional" argument named "X".


E.g.

xxx <- lapply(y,function(x,X){cos(x*X)},X=2*pi)

which produces the error message


Error in get(as.character(FUN), mode = "function", envir = envir) :
  object 'y' of mode 'function' was not found


This of course happens because the name of the first argument of 
lapply() is "X" and so it takes the value of this first argument to be 
the supplied X (2*pi in the foregoing example) and then expects what the 
user has denoted by "y" to be the value of FUN, and (obviously!) it isn't.


Once one realises what is going on, it's all quite obvious, and usually
pretty easy to fix.  OTOH there are lots of functions around with second
or third arguments whose formal name is "X", and these can trip one up
until the penny drops.

This keeps happening to me, over and over again (with sufficiently long
intervals between occurrences so that my ageing memory forgets the 
previous occurrence).


Is there any way to trap/detect the use of an optional argument called 
"X" and thereby issue a more perspicuous error message?


This would be helpful to those users who, like myself, are bears of very 
little brain.


Failing that (it does look impossible) might it not be a good idea to 
add a warning to the help for lapply(), to the effect that if FUN has an 
optional argument named "X" then passing this argument via "..." will 
cause this argument to be taken as the first argument to lapply() and 
thereby induce an error?


cheers,

Rolf Turner

--
Technical Editor ANZJS
Department of Statistics
University of Auckland
Phone: +64-9-373-7599 ext. 88276

__
R-devel@r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel