Evaluate call that contains another call (call within call)

后端 未结 5 1680
-上瘾入骨i
-上瘾入骨i 2021-02-19 06:41

I have encountered a snippet of code where call contains another call. For example:

a <- 1
b <- 2
# First call
foo <- quote(a + a)
# Second call (call c         


        
5条回答
  •  渐次进展
    2021-02-19 07:33

    I came up with a simple solution to this, but it seems a little improper and I hope that a more canonical method exists to cope with this situation. Nevertheless, this should hopefully get the job done.

    The basic idea is to iterate through your expression and replace the un-evaluated first call with its evaluated value. Code below:

    a <- 1
    b <- 2
    # First call
    foo <- quote(a + a)
    # Second call (call contains another call)
    bar <- quote(foo ^ b)
    
    bar[[grep("foo", bar)]] <- eval(foo)
    eval(bar)
    #> [1] 4
    

    So far this is pretty easy. Of course if your expressions are more complicated this becomes more complicated quickly. For instance, if your expression has foo^2 + a then we need to be sure to replace the term foo^2 with eval(foo)^2 and not eval(foo) and so on. We can write a little helper function, but it would need a good deal of work to robustly generalize to complexly nested cases:

    # but if your expressions are more complex this can
    # fail and you need to descend another level
    bar1 <- quote(foo ^ b + 2*a)
    
    # little two-level wrapper funciton
    replace_with_eval <- function(call2, call1) {
      to.fix <- grep(deparse(substitute(call1)), call2)
      for (ind in to.fix) {
        if (length(call2[[ind]]) > 1) {
          to.fix.sub <- grep(deparse(substitute(call1)), call2[[ind]])
          call2[[ind]][[to.fix.sub]] <- eval(call1)
        } else {
          call2[[ind]] <- eval(call1)
        }
      }
      call2
    }
    
    replace_with_eval(bar1, foo)
    #> 2^b + 2 * a
    eval(replace_with_eval(bar1, foo))
    #> [1] 6
    
    bar3 <- quote(foo^b + foo)
    
    eval(replace_with_eval(bar3, foo))
    #> [1] 6
    

    I thought I should somehow be able to do this with substitute() but couldn't figure it out. I'm hopeful a more authoritative solution emerges but in the meantime this may work.

提交回复
热议问题