Is it possible in R to make a piece of code run before every command?
Just an example of my usecase (not the actual usecase). printing hi before every command
> print(2)
> print(1)
should give
hi
2
hi
1
So, there should be a function say beforeTaskCall(print("hi"))
which will call print("hi")
before every line.
I found the addTaskCallback which will make a function run after every command.
To run a piece of code before a command you can redefine an unary operator and place this before the command.
`~` <- function(x) {print("hi"); eval(substitute(x))}
~print(2)
#[1] "hi"
#[1] 2
~print(1)
#[1] "hi"
#[1] 1
Other possible unary operators are -
, +
, ?
of !
.
Or use binary operator, in case it could be placed after the function
`?` <- function(x, .) {print("hi"); eval(substitute(x))}
print(2) ?.
#[1] "hi"
#[1] 2
Another option will be to store the commands as a string and iterate over them.
s <- c(r"(print(2)
print(1))")
for(x in strsplit(s, "\n")[[1]]) {
print("hi")
eval(parse(text=x))
}
#[1] "hi"
#[1] 2
#[1] "hi"
#[1] 1
Or make use of addTaskCallback
, which is calling the function afterwards but maybe it could be used in this setup.
invisible(id <- addTaskCallback(function(...) {print("hi"); TRUE}))
#[1] "hi"
print(2)
#[1] 2
#[1] "hi"
invisible(removeTaskCallback(id))
print(1)
#[1] 1
trace
Use trace
to insert arbitrary R expressions (R code) into any places inside a function.
f <- function(x) {
print(x * 10)
print(x * 100)
} # Our original function f
m <- expression(print("hello"), print("world")) # An expression m we want to insert into function f
# m <- quote({print("hello"); print("world")}) # Alternative way of defining m
# m <- substitute({print("hello"); print("world")}) # Alternative way of defining m
trace(f, tracer = m, print = FALSE) # Insert expression m at the beginning of function f
f # Check that this function is in trace mode, and read the instruction for seeing tracing code
body(f) # See that our code is inserted correctly
f(3)
[1] "hello"
[1] "world"
[1] 30
[1] 300
untrace(f) # Remove all tracing code
f(3)
[1] 30
[1] 300
With this approach you can insert code at any places inside a function utilizing tracer
, exit
, at
argument of trace
, or even interactively edit the function with edit = TRUE
argument:
Beginning:
trace(f, tracer = m, print = FALSE)
body(f)
{
.doTrace(expression(print("hello"), print("world")))
{
print(x * 10)
print(x * 100)
}
}
End:
trace(f, exit = m, print = FALSE)
body(f)
{
on.exit(.doTrace(expression(print("hello"), print("world"))))
{
print(x * 10)
print(x * 100)
}
}
Inside:
trace(f, m, at = 3, print = FALSE)
body(f)
{
print(x * 10)
{
.doTrace(expression(print("hello"), print("world")))
print(x * 100)
}
}
Interactive:
trace(f, edit = TRUE, print = FALSE)
# supply your custom version of f using an editor
body(f) # for checking
body(f)
f <- function(x) {
print(x * 10)
print(x * 100)
} # Our original function f
h_f <- f # copy function f as template
body(h_f) <- substitute({print("hello"); print("world"); m}, list(m = body(f))) # change only body(h_f) to suit our needs
# body(h_f) <- bquote({print("hello"); print("world"); .(body(f))}) # Alternative way of defining body(h_f)
h_f # to check the resulting h_f function
#function (x)
#{
# print("hello")
# print("world")
# {
# print(x * 10)
# print(x * 100)
# }
#}
h_f(3)
[1] "hello"
[1] "world"
[1] 30
[1] 300
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With