Get name of x when defining `(<-` operator

后端 未结 2 1682
无人及你
无人及你 2020-12-16 05:53

I want to define (<- and access the name of the left hand side argument :

*<- functions use internally an intermediate \'*tmp*\

相关标签:
2条回答
  • 2020-12-16 06:28

    I hacked it, though I didn't understand everything that I did.

    I noticed pryr::address was giving a different kind of results than tracemem and tried it (I had to dig into the code to use pryr:::address2 because pryr::address doesn't have an environment argument).

    Then I noticed that mixing the results from tracemem on x and pryr:::address2 on the rest of the objects there was a match (after basic reformatting) :

    `(<-` <- function(x,value){
      pf <- parent.frame()
      all_addresses       <- sapply(ls(pf), pryr:::address2, pf)
      all_addresses       <- all_addresses[names(all_addresses) != "*tmp*"]
      all_addresses_short <- gsub("(^|<)[0x]*(.*?)(>|$)","\\2",all_addresses)
    
      x_address       <- tracemem(x)
      x_address_short <- tolower(gsub("(^|<)[0x]*(.*?)(>|$)","\\2",x_address))
    
      ind    <- match(x_address_short, all_addresses_short)
      x_name <- names(all_addresses)[ind]
    
      message("all_addresses, using pryr::address2")
      print(all_addresses)
      print(all_addresses_short)
    
      message("x_address, using tracemem")
      print(x_address)
      print(x_address_short)
    
      message("x_name, matching substrings")
      print(x_name)
    
      value
    }
    

    The regex used in gsub calls tries to account for the address formats we get with different systems, I'm not 100% sure that it's general.

    output:

    foo <- 1
    bar <- 2
    (foo) <- foo
    
    # all_addresses, using pryr::address2
    # (<-          bar          foo 
    # "0x1433df50" "0x14937678" "0x14937708" 
    # (<-        bar        foo 
    # "1433df50" "14937678" "14937708" 
    # x_address, using tracemem
    # [1] "<0000000014937708>"
    # [1] "14937708"
    # x_name, matching substrings
    # [1] "foo"
    

    It breaks if x is not a variable name, for example:

    foo <- iris
    (foo$species) <- 3
    

    We could assume that if the address isn't found x is a list item, and then lookup its address among the addresses of the items of all the lists we have in the parent.frame (recursively), but I think that's enough ugly hacks for today.

    0 讨论(0)
  • 2020-12-16 06:35

    1) If you are willing to change it so that the call is:

    fooify[foo] <- 99
    

    then we can do it like this where foo need not exist beforehand:

    fooify <- structure(NA, class = "fooify")
    "[<-.fooify" <- function(x, var, value) {
      print(deparse(substitute(var)))
      eval.parent(substitute(var <- value))
      x
    }
    
    # test
    
    if (exists("foo")) rm(foo)
    fooify[foo] <- 99
    ## [1] "foo"  <-- this comes from the print statement
    foo
    ## [1] 99
    

    2) := If using := is ok then:

    `:=` <- function(lhs, rhs) {
      print(deparse(substitute(lhs)))
      eval.parent(substitute(lhs <- rhs))
    }
    
    # test
    if (exists("foo")) rm(foo)
    foo := 99
    ## [1] foo   <-- this comes from print statement
    foo
    ## [1] 99
    
    0 讨论(0)
提交回复
热议问题