# chapter 2 of Braun and Murdoch # required arguments are likely to be known, optionals should be named args(plot.default) # I often skip naming x and y plot.default # shows the value of the object with this name # Matloff chapter 1 rm(list = ls()) # counts the number of odd integers in x oddcount <- function(x) { k <- 0 for (n in x) { if (n %% 2 == 1) k <- k+1 } return(k) } oddcount(c(1,3,5)) oddcount(c(1,2,3,7,8,9)) n # n and k exist within function environment (in stack) k # and are thus lost on return of the function f <- function(x) x+y # very bad practice! f(5) y <- 3 f(5) # the arg y should have been passed to f explicitly hn <- hist(Nile) hn # functions can only return one object, # so they tend to return a list with lots of elements dput(hn) str(hn) # one break more than number of midpoints plot(hn) ?plot.histogram lines(hn) # does the same thing # This is straight from "An Introduction to R" ############################################################################### # chapter 10 frep<-function(word=c("Hello","World"),...) rep(word,...) frep() frep(word="hello",times=3) # times is passed via ... frep(times=3) frep(each=2,times=3) fun1 <- function(data, dataFrame, prtHead, limit) { print(data$ages) if (prtHead) print(head(dataFrame,3)) print(limit) } (df=data.frame(lets=LETTERS[1:4],gender=sample(c("males","females"),4,replace=T))) (d=list(no.children=3, ages=c(4,7,9))) # then these are all equivalent fun1(d, df, TRUE, 20) # without names, the order must match fun1(d, df, prtHead=TRUE, limit=20) # named args can come in any order fun1(data=d, limit=20, prtHead=TRUE, dataFrame=df) fun1(d, prtHead=TRUE,df, limit=20) # the rest must be in the right order fun1(limit=20, prtHead=TRUE,d, df) fun1(limit=20, prtHead=TRUE,df, d) # here they are not in the right order f <- function(x) { y <- 2*x print(x) print(y) cat("z=",z,"\n") } #In this function, x is a formal parameter, y is a # local variable and z is a free variable. rm(z) f(3) # f is bound to the global environment, since it is defined in it z=2 # but that environment isn't a frozen snapshot, i.e. we can add z=2 to it f(3) X=3 nova<-function() X<-5 nova() X nova<-function() X<<-5 nova() X X=3 nova<-function() { assign("X",5,pos=2) print(X) } nova() X ######################################################### ### Matloff Chapter 7 (u=matrix(c(1:3,1,2,4),nrow=3)) (v=matrix(c(8,12,20,5,10,2),nrow=3)) for (m in c("u","v")) { z=get(m) # use to fetch value when variable name is a string print(m) # print(summary(lm(z[,2]~z[,1]))) print(lm(z[,2]~z[,1])) } g=function(x) x+1 formals(g) (bd=body(g)) class(bd) # class call bd[[1]] # expressions are lists of calls bd[[2]] bd[[3]] g edit(abline) # pops it open in an extra editor sum # many functions are coded in C; .Primitive indicates this f1=function(a,b) a+b f2=function(a,b) a-b f=f1 f(3,2) f=f2 f(3,2) g=function(h,a,b) h(a,b) g(f1,3,2) g(f2,3,2) plot(c(0,1),c(-1,1.5)) g1=function(x) sin(x) g2=function(x) sqrt(x^2+1) g3=function(x) 2*x-1 x=seq(0,1,0.05) for (f in c(g1,g2,g3)) lines(x,f(x)) c(g1,g2,g3) # unnamed list of functions g=function(x) sin(x) g body(g) class(body(g)) g(0) body(g)<-quote(2*x-1) # without quote, value of 2*x-1 would go into body as a constant g(0) g # back to expression example at end of lists.R in week3 (ep<-parse(text="4*(2+3)")) # make an expression from a string class(ep) eval(ep) ep[[1]] # expressions are like lists class(ep[[1]]) eval(ep[[1]]) # calls can also be eval-ed ep[[1]][[1]] class(ep[[1]][[1]]) # function names in calls are of class name ep[[1]][[2]] class(ep[[1]][[2]]) ep[[1]][[3]] ep[[1]][[3]][[1]] ep[[1]][[3]][[2]] class(ep[[1]][[3]][[2]]) # class call # conclusion: expressions are made up of calls, the expression was the whole # tree. There were no expressions inside of the expression. rm(list=ls(all=TRUE)) # clear all variables f=function(y) { d=8 print(environment(h)) # prints h(d,y) # no h but no error since lazy eval => no problem until evaluated } h=function(dee,yyy) { print(ls()) # local environment within function, only args exists print(ls(envir=parent.frame(n=1))) # one up is envir within f which calls it print(ls(envir=.GlobalEnv)) # global is the same print(ls(envir=parent.frame(n=2))) # as 2 up dee*yyy } f(2) # h exists when f is called # now pass the function h to f as an argument f=function(y,ftn) { d=8 print(environment(ftn)) ftn(d,y) } f(2,h) # even though ftn is local to f, its value h comes with its own environment, # which was set to be .GlobalEnv since that's where it was defined. counter=function() { ctr=0 function(){#counter returns this function, bound to its environ (ctr=0) ctr<<-ctr+1 cat("This counter's current value is",ctr,".\n") } } c1=counter() # counter returns a closure, i.e. function with # an environment that contains ctr initiated at 0 c2=counter() # second separate closure c1 c2 # they look the same, but note that their environment numbers are different c1() c1() c1() c2() c2() c1() c2() "%a2b%"=function(a,b) 2*a+b # percents allow use as a binary operator 2%a2b%3 ###################################### ## Ligges Chap 4 lazy=function(x,y=TRUE){ if (y) x=x+1 print(a) } lazy((a<-3),y=F) # since x isn't actually used, first arg isn't evaluated lazy((a<-3)) # now default is true, so x=x+1 is called, so first arg is evaluated y=function(x) list(call=substitute(x),value=x) (lstOut=y(1+2)) lapply(lstOut,class) scope=function(do.it=TRUE){ if (do.it) x=3 innerFunc=function() print(x) # innerFunc() } x=5 scope(do.it=FALSE) # grab from global is not called scope() # use default so now called, so use local # pick up here rm(list=ls()) scope2=function(){ onlyHere="I'm only defined here" innerFunc=function() print(onlyHere) return(innerFunc) } out=scope2() ls(environment(out)) ls(environment(scope2)) #scope2 can be written with fewer characters like this scope2=function(){ onlyHere="I'm only defined here" function() print(onlyHere) } out=scope2() ls(environment(out)) (mycall<-call("round",12.4321,digits=2)) mode(mycall) eval(mycall) mycall deparse(mycall)# back to string, e.g. plot(x,sin(x)) makes ylab="sin(x)" do.call("round",list(12.4321,digits=2)) # makes call and evaluates it (qr=quote(round(12.4321, digits = 2))) # looks like a call class(qr) # indeed it is eval(qr) s1="round(12.4321, digits = 2)" (e1=parse(text=s1)) # in general, expressions are like lists of calls mode(e1) # e1 is like a simple list of length 1 eval(e1) rm(list=ls()) f=function(x) y=x f(12) #nothing returned .Last.value # last number returned by a function (z=f(12)) # but if asked for, something is returned print(f(12)) # recall that, when asked, the if else construct returned values even when # assigned f=function(x) x f(12) f=function(x) return(x) f(12) f=function(x) (y=x) f(12) # but as shown above, f=function(x) y=x f(12)