R again!
You know how in Matlab you can do?
S, I = sort(M)
I like that.
R generic functions makes this possible. First, let’s genericize assignment. I feel like regular “=” and “<-” oughta stay nongeneric, so let’s make a new one.
'%=%' = function(l, r, ...) UseMethod('%=%')
Now the next step is a bit tricky. We need to group several variables on the left of %=%
... a, b, ... %=% foo()
The trick is they have to stay unevaluated. Luckily R uses (what IIRC is called) “pass by name”, so we can do this. Let’s start with a function to take a, b, …
l = function(...) {
}
The hard part is grabbing the ‘…’ without evaluating it.
> substitute(...) ...
won’t work, nor will alist(…). I have NO IDEA why, but the following expression (stolen from data.frame()) works:
as.list(substitute(list(...)))[-1L]
So now we have our function
l = function(...) {
List = as.list(substitute(list(...)))[-1L]
class(List) = 'lbunch'
List
}
And we can add a specific implementation for our generic %=%:
'%=%.lbunch' = function(l, r, ...) {
Names = lapply(l, as.character)
Envir = as.environment(-1)
for (II in 1:length(Names)) {
Name = Names[[II]]
assign(Name, r[[II]], pos=Envir)
}
}
Which just treats the objects “a”, “b” … as strings, and assigns into the caller’s environment.
That’s what I had first, but it can be made better. With the above implementation:
> l(a[1], b) %=% list(3, 4) Warning message: In assign(Name, r[[II]], pos = Envir) : only the first element is used as variable name
It doesn’t play nice with assignment functions.
It can be modified to call ‘<-’ directly:
'%=%.lbunch' = function(l, r, ...) {
Envir = as.environment(-1)
for (II in 1:length(l)) {
do.call('<-', list(l[[II]], r[[II]]), envir=Envir)
}
}
And now all is good.
> l(attr(a, 'foo'), b) %=% list(3, 4) > a [1] 3 attr(,"foo") [1] 3
How about
x <- y <- myvalue
or
S = I = sort(M)?
Is this what you're trying to do?
Hi Josh,
I’m looking to assign different values to the two variables. Looking at my post, it wasn’t at all clear _why_ I wanted to do that, but the reason is:
How do you return multiple values from a function?
Well in R, you return them in a list. This works perfectly well. But there are times when a little syntactic sugar is nice. Say you had a function that consumed blocks of an array, say like
next.block = function(Array) {
Zeros = which(Array==0)
Start = 1
if (length(Zeros) > 1) {
Stop = min(Zeros)
}
else {
Stop = length(Array)
}
Block = Array[Start:(Stop-1)]
Rest = Array[(Stop+1):length(Array)]
list(Block, Rest)
}
Array = c(1, 2, 5, 0, 10, 9, 0, 1, 0, 4)
l(B1, Array) %=% next.block(Array)
l(B2, Array) %=% next.block(Array)