Search code examples
rlapplypurrrnames

Why don't lambda functions handle replacement functions in their intuitive form?


Why don't lambda functions handle replacement functions in their natural form? For example, consider the length<- function. Say I want to standardize the lengths of a list of objects, I may do something like:

a <- list(c("20M1", "A1", "ACC1"), c("20M2", "A2", "ACC2"), c("20M3"))

mx <- max(lengths(a))

lapply(a, `length<-`, mx)
#> [[1]]
#> [1] "20M1" "A1"   "ACC1"
#> 
#> [[2]]
#> [1] "20M2" "A2"   "ACC2"
#> 
#> [[3]]
#> [1] "20M3" NA     NA

However if I wanted to specify the argument input locations explicitly using a lambda function I'd need to do (which also works):

lapply(a, function(x) `length<-`(x, mx))

But why doesn't the more intuitive notation for replacement functions (see below) work?

lapply(a, function(x) length(x) <- mx)
#> [[1]]
#> [1] 3
#> 
#> [[2]]
#> [1] 3
#> 
#> [[3]]
#> [1] 3

This returns an output I did not expect. What is going on here? Lambda functions seem to handle the intuitive form of infix functions, so I was a little surprised they don't work with the intuitive form of replacement functions. Why is this / is there a way to specify replacement functions in lambda functions using their intuitive form?

(I imagine it has something to do with the special operator <-... but would be curious for a solution or more precise explanation).


Solution

  • Whenever you do an assignment in R, the value returned from that expression is the right hand side value. This is true even for "special" versions of assign functions. For example if you do this

    x <- 1:2; y <- (names(x) <- letters[1:2])
    > y
    [1] "a" "b"
    

    You can see that y gets the values of the names, not the updated value of x.

    In your case if you want to return the updated value itself, you need to do so explicitly

    lapply(a, function(x) {length(x) <- mx; x})