4. 函数

作者: kkkkkkang | 来源:发表于2020-04-15 15:44 被阅读0次

    Ok,开始新的一章。基本的我就不写了,只写应该注意的地方和坑。代码基本都是来源于书上,少部分是我自己加上去的

    • 重新开始(别误会,是函数)
    > j <- function() {
      if (!exists("a")) {
        a <- 1
      } else {
        a <- a + 1
      }
      a
    }
    > j()
    [1] 1
    > j()
    [1] 1
    #因为每次调用这个函数都会创建一个新环境,函数不可能知道上次被调用时发生了什么,每次调用都是独立的
    
    • 动态查找,这个地方可以用来使坏😈
    > f <- function() x
    > x <- 15
    > f()
    [1] 15
    > x <- 20
    > f()
    [1] 20
    #然而,这样函数就不是独立的了,可以使用codetools::findGlobals()查看一个函数额所有外界依赖关系
    > f <- function() x + 1
    > codetools::findGlobals(f)
    [1] "+" "x"
    #使用emptyenv()清空环境不现实,这样你连"+"都用不了了。所以这样别人就有可能使坏了
    #比如:趁你不在,把"("的这个函数给改掉—有1/10的概率得到比输入值大1的数
    > `(` <- function(e1) {
      if (is.numeric(e1) && runif(1) < 0.1) {
        e1 + 1
      } else {
        e1
      }
    }
    > replicate(50, (1 + 2))
    > replicate(50, (1 + 2))
     [1] 3 3 3 3 3 3 3 3 3 3 3 3 3 4 4 4 3 3 3 3 3 3 3 4 3 3 3 3 4 3 3 3 3 3 3 3 3 3
    [39] 3 3 3 3 3 3 4 3 3 3 4 3
    #看看,是的吧。解决方法很简单
    > rm("(")
    > replicate(50, (1 + 2))
     [1] 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3
    [39] 3 3 3 3 3 3 3 3 3 3 3 3
    #重归于好,哈哈哈。这里不是教人使坏,其实是警示大家在开始R会话之前,尽量清空之前对话的数据
    > rm(list = ls())
    
    • 习题
    > f <- function(x) {
    +     f <- function(x) {
    +         f <- function(x) {
    +             x ^ 2
    +         }
    +         f(x) + 1
    +     }
    +     f(x) * 2
    + }
    > f(10)
    #在脑子里过一下这个会得到什么结果
    好吧,答案是202
    #解答思路:最内层函数要向外找变量值10,f(x) +1 值就成了101,然后f(x)*2就是202
    
    • 自定义中缀运算符及其优先级调整策略
    > `%foo%` <- `+`
    > 2 %foo% 4
    [1] 6
    > `%mul%` <- `*`
    > 2 %foo% 4 %mul% 3
    [1] 18
    #默认优先级是从左到右的,调整优先级,加括号就行了
    > 2 %foo% (4 %mul% 3)
    [1] 14
    
    • 中缀函数:一般都是函数在参数的前面,可以使用中缀函数把函数放到参数的中间。另外我们可以自定义并且利用`(tab键上面的那个) 引用预留的或自定义(非法)的函数
    > `%mul%`(3,4)
    [1] 12
    x <- 10; y <- 5
    x + y
    #> [1] 15
    `+`(x, y)
    #> [1] 15
    
    for (i in 1:2) print(i)
    #> [1] 1
    #> [1] 2
    `for`(i, 1:2, print(i))
    #> [1] 1
    #> [1] 2
    
    if (i == 1) print("yes!") else print("no.")
    #> [1] "no."
    `if`(i == 1, print("yes!"), print("no."))
    #> [1] "no."
    
    x[3]
    #> [1] NA
    `[`(x, 3)
    #> [1] NA
    
    { print(1); print(2); print(3) }
    #> [1] 1
    #> [1] 2
    #> [1] 3
    `{`(print(1), print(2), print(3))
    #> [1] 1
    #> [1] 2
    #> [1] 3
    

    上面这个思想和apply结合可以自编函数来处理每个元素,实现想要的功能

    > add <- function(x, y) x + y
    > sapply(1:10, add, 3)
     [1]  4  5  6  7  8  9 10 11 12 13
    > sapply(1:5, `+`, 3)
    [1] 4 5 6 7 8
    > sapply(1:5, "+", 3)
    [1] 4 5 6 7 8
    > x <- list(1:3, 4:9, 10:12)
    > sapply(x, "[", 2)
    [1]  2  5 11
    > sapply(x, function(x) x[2])
    [1]  2  5 11
    
    • 函数参数
    #使用参数列表来传递函数参数
    > args <- list(1:10, na.rm = TRUE)
    > do.call(mean, args)
    [1] 5.5
    #等同于
    > mean(1:10,na.rm = TRUE)
    [1] 5.5
    #默认参数
    > f <- function(a = 1, b = 2) {
      c(a, b)
    }
    > f()
    #> [1] 1 2
    #默认参数可以使用其它参数来求值
    g <- function(a = 1, b = a * 2) {
      c(a, b)
    }
    g()
    #> [1] 1 2
    g(10)
    #> [1] 10 20
    #默认参数甚至可以是隐藏在函数内部的变量(这并不推荐)
    h <- function(a = 1, b = d) {
      d <- (a + 1) ^ 2
      c(a, b)
    }
    h()
    #> [1] 1 4
    h(10)
    #> [1]  10 121
    #像上面这种,默认参数需要很长的计算才能得到,通常建议使用missing()函数判断,有需要再计算。
    #缺点:不阅读文档就不知道那个参数是必须的。可以把默认参数设置成NULL,is.null()去判断参数是否设置了
    
    • 终止函数stop()
    > a <- function(x){
      for (i in 1:x){
        print(i)
        if (i == 3){
          stop("Error:3 is an error number")
        }
      }
    }
    > a(4)
    [1] 1
    [1] 2
    [1] 3
    Error in a(4) : Error:3 is an error number
    
    • 惰性求值,即只在使用函数参数时,对其求值;有时可以用来删除一个if语句
    > f <- function(a,b){
    +   print(a)
    + }
    > f(2)
    [1] 2
    > f_1 <- function(a,b){
    +   print(a)
    +   print(b)
    + }
    > f_1(8)
    [1] 8
    Error in print(b) : 缺少参数"b",也没有缺省值
    ************************************************************
    > a <- NULL
    > if (is.null(a)) stop("a is null")
    错误: a is null
    > !is.null(a) || stop("a is null")
    错误: a is null
    > is.null(a) || stop("a is null")
    [1] TRUE
    

    ...参数:它可以传递一个函数的参数到另一个函数(可以利用这个特性修改已知函数的参数,而不必列出所有原函数的参数);当传递到函数的参数数量不能确定的时候,它必须被使用

    #用来传参
    > new_plot <- function(x,y,type = "s",...){
      plot(x,y,...)
    }
    #参数个数不确定
    > num <- function(...,sep = "_"){
    +   paste(...,sep = sep)
    + }
    > num(1,2,3)
    [1] "1_2_3"
    
    • 对函数的参数进行修改,不会改变参数的原始值
    > f <- function(x) {
    +     x$a <- 2
    +     x
    + }
    > x <- list(a = 1)
    > f(x)
    $a
    [1] 2
    > x$a
    [1] 1
    
    • invisible()函数详解
    f1 <- function() 1
    f2 <- function() invisible(1)
    f1()
    #> [1] 1
    f2()
    f1() == 1
    #> [1] TRUE
    f2() == 1
    #> [1] TRUE
    ********************************************************
    #可以使用括号,强制显示
    (f2())
    #> [1] 1
    #最常用的隐藏返回值的函数应该是"<- "了,这样可以把一个值赋给多个变量
    a <- b <- c <- d <- 2
    

    on.exit()前面一章已经说过了,需要注意的是:如果在一个函数中使用多个on.exit(),一定要加上参数add = TRUE。不加的话,每次运行on.exit()后,它将重写退出表达式

    相关文章

      网友评论

        本文标题:4. 函数

        本文链接:https://www.haomeiwen.com/subject/qgexvhtx.html