From es at enricoschumann.net  Wed Mar 29 09:32:54 2017
From: es at enricoschumann.net (Enrico Schumann)
Date: Wed, 29 Mar 2017 09:32:54 +0200
Subject: [Rd] A trap for young players with the lapply() function.
In-Reply-To: <5c05350f-ea20-b8c2-5f97-2af3a05f9052@auckland.ac.nz> (Rolf
	Turner's message of "Tue, 28 Mar 2017 10:26:54 +1300")
References: <4e15ccb966c041f68ea042459324d02c@EX-0-HT0.lancs.local>
	<CANVKczOEg6e3b7U1rYd1nQzJQOtxXGc+e=6cvHJJVFSsxcovAQ@mail.gmail.com>
	<5c05350f-ea20-b8c2-5f97-2af3a05f9052@auckland.ac.nz>
Message-ID: <87d1d0a66x.fsf@enricoschumann.net>

(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 <r.turner at auckland.ac.nz> 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 purrrring 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



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