Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/r/67.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在R中使用宏安全吗?_R_Macros - Fatal编程技术网

在R中使用宏安全吗?

在R中使用宏安全吗?,r,macros,R,Macros,我使用gtools软件包中的defmacro函数在R中编写了一些宏: #' IfLen macro #' #' Check whether a object has non-zero length, and #' eval expression accordingly. #' #' @param df An object which can be passed to \code{length} #' @param body1 If \code{length(df)} is not zero

我使用
gtools
软件包中的
defmacro
函数在R中编写了一些宏:

#' IfLen macro
#' 
#' Check whether a object has non-zero length, and 
#' eval expression accordingly.
#' 
#' @param df An object which can be passed to \code{length}
#' @param body1 If \code{length(df)} is not zero, then this clause is evaluated, otherwise, body2 is evaluated.
#' @param body2 See above.
#' @importFrom gtools defmacro
#' 
#' @examples 
#' ifLen(c(1, 2), { print('yes!') }, {print("no!")})
#' 
#' @author kaiyin
#' @export
ifLen = gtools::defmacro(df, body1, body2 = {}, expr = {
            if(length(df) != 0) {
                body1
            } else {
                body2
            }
        })

#' IfLet macro
#' 
#' Eval expression x, assign it to a variable, and if that is TRUE, continue
#' to eval expression1, otherwise eval expression2. Inspired by the clojure 
#' \code{if-let} macro.
#' 
#' @param sym_str a string that will be converted to a symbol to hold value of \code{x}
#' @param x the predicate to be evalueated, and to be assigned to a temporary variable as described in \code{sym_str}
#' @param body1 expression to be evaluated when the temporary variable is TRUE.
#' @param body2 expression to be evaluated when the temporary variable is FALSE.
#' @importFrom gtools defmacro
#' 
#' @examples 
#' ifLet("..temp..", TRUE, {print(paste("true.", as.character(..temp..)))}, 
#'      {print(paste("false.", as.character(..temp..)))})
#' 
#' @author kaiyin
#' @export
ifLet = gtools::defmacro(sym_str, x, body1, body2={}, expr = {
            stopifnot(is.character(sym_str))
            stopifnot(length(sym_str) == 1)
            assign(sym_str, x)
            if(eval(as.symbol(sym_str))) {
                body1
            } else {
                body2
            }
        })

#' IfLetLen macro
#' 
#' Similar to ifLet, but conditioned on whether the length of 
#' the result of \code{eval(x)} is 0.
#' 
#' 
#' @param x the predicate to be evalueated, and to be assigned to a temporary var called \code{..temp..}
#' @param body1 expression to be evaluated when \code{..temp..} is TRUE.
#' @param body2 expression to be evaluated when \code{..temp..} is FALSE.
#' @importFrom gtools defmacro
#' 
#' @examples 
#' ifLetLen("..temp..", 1:3, {print(paste("true.", as.character(..temp..)))}, 
#'      {print(paste("false.", as.character(..temp..)))})
#' 
#' @author kaiyin
#' @export
ifLetLen = gtools::defmacro(sym_str, x, body1, body2={}, expr = {
            stopifnot(is.character(sym_str))
            stopifnot(length(sym_str) == 1)
            assign(sym_str, x)
            ifLen(eval(as.symbol(sym_str)), {
                body1
            }, {
                body2
            })
        })

使用它们有危险吗?

当然你必须小心。宏没有自己的环境

简单示例f(x,y)=(x+y)^2:

正常R函数的行为不同:

f1 <- function(x, y) {
  x <- x + y
  x*x
}

> x <- 1
> y <- 2
> f1(x, y)
[1] 9
> x
[1] 1
> y
[1] 2 
f1 x
[1] 1
>y
[1] 2 

从未听说过他们。我认为他们会在运行中生成代码。为什么要使用这些函数而不是函数,特别是考虑到R强大的查看自己代码的能力?存在一种潜在的危险,即宏没有自己的环境。有关更多信息,请参阅帮助页()上提到的Thomas Lumley R-news文章。插图精美。你也能看看这个吗?
> x <- 1
> y <- 2
> m1(x, y)
[1] 9
> x
[1] 3
> y
[1] 2
f1 <- function(x, y) {
  x <- x + y
  x*x
}

> x <- 1
> y <- 2
> f1(x, y)
[1] 9
> x
[1] 1
> y
[1] 2