Nesse capítulo veremos como criar funções dentro do R para tornar nosso código mais dinâmico e prático. Além disso será apresentado o conceito de variável local, que é de grande importância em qualquer linguagem de programação.
Uma função dentro dentro de uma linguagem de programação é definida pelos seguintes itens:
Tanto os argumentos de entrada quanto a saída de uma função podem ser nulos, ou vazios, mas em geral eles são definidos.
Depois que uma função é definida para executar a sua sequência de comandos basta chamá-la pelo nome, passando os argumentos de entrada caso estes não sejam nulos. Veremos alguns exemplos ao longo do capítulo.
Para definir uma nova função no R deve ser usada a seguinte sintaxe.
nome_da_funcao <- function(argumentos){
# sequencia de comandos
return(saida)
}
Nome | Descrição |
---|---|
Argumentos: | Define as variáveis cujos valores serão atribuídos pelo usuário quando a função for chamada. |
Corpo da Função: | Contém os cálculos e tarefas executadas pela função. |
Retorno: | Indica qual o valor que a função retorna como saída. |
Vejamos alguns exemplos. Primeiro vamos construir uma função que retorna o maior entre dois valores passados como argumentos. Essa função já existe pronta no R e se chama , o que vamos fazer é entender como ela funciona criando a nossa própria função.
maior <- function(a,b){
if(a>b)
return(a)
else
return(b)
}
Depois da função definida e compilada podemos chamá-la sem ter que digitar todo o código novamente. Veja o que acontece quando a função é chamada no prompt do R.
maior(3,2)
## [1] 3
maior(-1,4)
## [1] 4
maior(10,10)
## [1] 10
maior("A","B")
## [1] "B"
Também podemos optar por guardar a saída da função em uma variável, o que pode ser bastante útil.
x = maior(-5,-3)
y = 2*x
x
## [1] -3
y
## [1] -6
E se quiséssemos encontrar o maior entre 3 números? Temos duas alternativas. A primeira é usar a função acima composta com ela mesma. Veja como.
maior(1,maior(2,5))
## [1] 5
maior(10,maior(6,-1))
## [1] 10
maior(-3,maior(0,1))
## [1] 1
Outra alternativa é criar uma nova função com três argumentos própria para isso.
maior_de_3 <- function(a,b,c){
if(a>b && a>c){
return(a)
} else {
if(b>c)
return(b)
else
return(c)
}
}
y <- maior_de_3(2,15,6)
y
## [1] 15
Vamos agora fazer uma função que recebe como argumento um número natural n
e retorna um array com os n
primeiros múltiplos de 3. Nas atividades práticas do último capítulo fizemos isso para n=100
, agora a ideia é criar uma função que realizará essa tarefa para qualquer n
escolhido pelo usuário.
multiplos_3 <- function(n){
vet <- NULL
for(i in 1:n){
vet[i] <- 3*i
}
return(vet)
}
multiplos_3(10)
## [1] 3 6 9 12 15 18 21 24 27 30
multiplos_3(15)
## [1] 3 6 9 12 15 18 21 24 27 30 33 36 39 42 45
E se colocarmos como argumento um número que não seja natural, o que acontece? A função executa os comandos considerando o n
que foi passado como argumento.
multiplos_3(1.5)
## [1] 3
multiplos_3(-1)
## [1] 3
Caso o programador não queira que um usuário use essa função para números não naturais ele precisa dentro da função checar se o valor de n
passado pelo usuário está correto. Caso o valor não seja correto é possível usar a função stop
para imprimir uma mensagem de erro e interromper a execussão da função.
Veja um exemplo para a função multiplos_3
, onde o argmento n
será restrito para os naturais.
multiplos_3 <- function(n){
if((n<=0)||(n%%1 != 0)){
stop("n tem que ser um numero natural")
}
vet <- NULL
for(i in 1:n){
vet[i] <- 3*i
}
return(vet)
}
As variáveis locais são aquelas usadas somente dentro do corpo da função. Para garantirmos que essa variável realmente não está assumindo um valor pré definido é preciso que ela seja iniciada dentro do corpo da função.
Reveja o código da função multiplos_3
. Veja que a variável vet
é um variável que só faz sentido dentro da função, está é uma variável local. Ao digitar vet <- NULL
garantimos que essa variável dentro da função vai sempre começar como nula. Se essa linha de comando for omitida, a função pode retornar resultados não esperados pelo programador. Vejaomos alguns exemplos. Primeiro a forma correta.
vet = c(1:10)
m = multiplos_3(5)
m
## [1] 3 6 9 12 15
vet
## [1] 1 2 3 4 5 6 7 8 9 10
Veja no código acima que tanto m
quanto vet
gurdam os valores esperados tanto pelo programador quanto pelo usuário. O usuário da função multiplos_3
não tem como saber que dentro dessa função existe uma variável local chamada vet
, então ele pode usar esse mesmo nome para outra variável, e isso não deve ser um problema.
Veja agora o que acontece se na função a variável local vet
não for iniciada. Para isso a função multiplos_3
será implementada de maneira errada.
multiplos_3_errada <- function(n){
if((n<=0)||(n%%1 != 0)){
stop("n tem que ser um numero natural")
}
for(i in 1:n){
vet[i] <- 3*i
}
return(vet)
}
Fazendo o mesmo teste que antes, agora com a função errada, veja o que acontece com variável m
, que é a saída da função.
vet = c(1:10)
m = multiplos_3_errada(5)
m
## [1] 3 6 9 12 15 6 7 8 9 10
vet
## [1] 1 2 3 4 5 6 7 8 9 10
Já a variável vet
criada pelo usuário permanece a mesma mesmo após a função multiplos_3_errada
ser chamada.
Dentro de uma função podemos ter dois tipos de variáveis:
Os argumentos de entrada não podem ser iniciados dentro do corpo da função, nesse caso perderíam o valor informado pelo usuário. Já as variáveis locais, aquelas que não foram passadas como argumento, tem que ser iniciadas dentro da função.
Veja mais um exemplo de função antes da seção de exercícios. Suponha que queremos criar uma função que em vez de retornar os n
primeiros múltiplos de 3 passe a retornar os n
primeiros múltiplos de m
.
multiplos <- function(n,m){
if((n<=0)||(n%%1 != 0)){
stop("n tem que ser um natural")
}
if((m<=0)||(m%%1 != 0)){
stop("m tem que ser um natural")
}
vet <- NULL
for(i in 1:n){
vet[i] <- m*i
}
return(vet)
}
multiplos(10,7)
## [1] 7 14 21 28 35 42 49 56 63 70
Mas essa não é a única maneira de implementar tal função. Podemos fazer isso de várias forma diferete, por exemplo, usando os controles de fluxo while
ou repeat
.
multiplos_while <- function(n,m){
if((n<=0)||(n%%1 != 0)){
stop("n tem que ser um natural")
}
if((m<=0)||(m%%1 != 0)){
stop("m tem que ser um natural")
}
vet = NULL
i = 0 #i representa quantos elementos ja foram alocados em vet
while(i<n){
i = i + 1
vet = c(vet,m*i)
}
return(vet)
}
multiplos_while(10,7)
## [1] 7 14 21 28 35 42 49 56 63 70
multiplos_repeat <- function(n,m){
if((n<=0)||(n%%1 != 0)){
stop("n tem que ser um natural")
}
if((m<=0)||(m%%1 != 0)){
stop("m tem que ser um natural")
}
vet = NULL
i = 0
repeat{
if(i >= n){
break
}
i = i + 1
vet = c(vet,m*i)
}
return(vet)
}
multiplos_repeat(10,7)
## [1] 7 14 21 28 35 42 49 56 63 70