Matlab-style multiple assignment in R

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
About these ads
This entry was posted in R. Bookmark the permalink.

2 Responses to Matlab-style multiple assignment in R

  1. josh goldstein says:

    How about

    x <- y <- myvalue

    or

    S = I = sort(M)?

    Is this what you're trying to do?

  2. ellbur says:

    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)

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s