Writing a decorator for R functions

后端 未结 2 498
小鲜肉
小鲜肉 2021-02-04 01:48

A colleague recently was looking at call graphs and wanted to see what called what. We sorted that with foodweb from mvbutils, but I was wondering about how best to create a dec

相关标签:
2条回答
  • 2021-02-04 01:57

    The trace function in R does that. See ?trace.

    0 讨论(0)
  • 2021-02-04 02:17

    my github package tag attempts to tackle this issue.

    Your example could be solved as follows :

    # remotes::install_github("moodymudskipper/tag")
    library(tag)
    deco <- tag(args = list(.first = NULL, .last = NULL), pattern = {
      t_args <- T_ARGS()                       # fetch arguments fed to tag
      eval.parent(t_args[[".first"]])          # run .first arg
      on.exit(eval.parent(t_args[[".last"]]))  # run .last arg on exit
      CALL()                                   # run main call
    })
    
    
    foo <- function(x, y) {Sys.sleep(1); x + y} # sleep 1 sec to highlight expected behavior
    
    deco(quote(message("calling foo")), quote(message("done")))$foo(1, 2)
    #> calling foo
    #> done
    #> [1] 3
    
    foo2 <- deco(quote(message("calling foo")), quote(message("done")))$foo
    foo2(1, 2)
    #> calling foo
    #> done
    #> [1] 3
    
    deco2 <- deco(quote(message("calling foo")), quote(message("done")))
    deco2$foo(1, 2)
    #> calling foo
    #> done
    #> [1] 3
    

    Created on 2020-01-30 by the reprex package (v0.3.0)

    tags are function operator factories (or adverb factories), here deco is a tag, and deco(quote(message("calling foo")), quote(message("done"))) is an adverb, with a method for $. It means you could run deco(quote(message("calling foo")), quote(message("done")))(foo)(1,2), but the dollar notation makes it friendlier.

    The tag definition features defaults arguments (default value is mandatory, dots aren't supported), and a pattern which is a bit like your new body, using special functions T_ARGS(), F_ARGS(), F_ARGS(), F_FORMALS() and CALL() to access the tag or function's arguments or formals and the call itself (see ?tag::CALL).

    Some more magic is implemented so the tag's argument can be given to the tagged function itself, so the following can be done too :

    deco$foo(1, 2, quote(message("calling foo")), quote(message("done")))
    #> calling foo
    #> done
    #> [1] 3
    foo2 <- deco$foo
    foo2(1, 2, quote(message("calling foo")), quote(message("done")))
    #> calling foo
    #> done
    #> [1] 3
    

    In these cases you can enjoy the autocomplete in RStudio :

    More info : https://github.com/moodymudskipper/tag The package tags contains a collection of such "decorators"

    0 讨论(0)
提交回复
热议问题