O novo pipe chegou
A profecia estava correta: o R finalmente ganhou um pipe próprio, embutido
à linguagem em si. Mais de 7 anos depois do
primeiro commit
do {magrittr}
, o %>%
, operador com o qual compartilhamos tantas boas
memórias, sÃmbolo do R moderno e inspiração para o logo da
Curso-R, vai se tornar obsoleto. De acordo com a
agenda do R Project, no badalar da
meia-noite do dia 18/05/2021 foi lançada oficialmente a versão 4.1.0 (“Camp
Pontanezen”) do R, contendo, dentre outras novidades, suporte para o operador
|>
.
Devo admitir que estou um pouco triste com a despedida, como se eu estivesse prestes a mudar de casa: pode ser que a casa nova seja melhor e maior, mas, de uma forma ou de outra, estou abandonando um lugar que foi palco de várias boas memórias por um lugar estéril e inerte…
Só que mesmo assim nós seguimos em frente e mudamos de casa! As lembranças não vão embora e temos a oportunidade de criar mais boas memórias com esse novo plano de fundo. Sendo assim, vamos entender as principais mudanças do R 4.1 e, principalmente, como usar o novo pipe.
O novo pipe: |>
À primeira vista, o novo pipe é igual ao antigo: usado no final de uma linha para passar o resultado do que está à sua esquerda como primeiro argumento da linha debaixo. Aqui temos um exemplo simples do uso mais comum dos pipes:
library(dplyr)
# Uma pipeline com o pipe novo
starwars |>
group_by(species, sex) |>
select(species, sex, height) |>
summarise(height = mean(height, na.rm = TRUE)) |>
pull(height) |>
summary()
#> Min. 1st Qu. Median Mean 3rd Qu. Max.
#> 66.0 163.0 181.3 173.5 196.0 264.0
As diferenças aparecem quanto tentamos usar o .
, a saber, o dot placeholder.
Bem comum no antigo pipe, o uso do .
para escolher onde a substituição deve
ocorrer é simplesmente proibido no novo pipe. Essa decisão foi tomada porque o
.
gera situações ambÃguas como a descrita a seguir:
# Vamos gerar essa string a partir de "-" %>% paste0()
"-><-"
#> [1] "-><-"
# Podemos começar colando o hÃfen na esquerda
"-" %>%
paste0(">")
#> [1] "->"
# Agora adicionamos o . para colar na direita também...
# Mas isso dá errado!
"-" %>%
paste0("><", .)
#> [1] "><-"
# Precisamos colocar o . em dois lugares diferentes,
# incluindo, contraintuitivamente, no primeiro argumento
"-" %>%
paste0(., "><", .)
#> [1] "-><-"
Assim, em troca de nunca mais precisar carregar o {magrittr}
, usar
usethis::use_pipe()
ou se preocupar com o ambiente do {future}
, vamos ser
obrigados a criar funções parciais que sempre esperam a substituição no seu
primeiro argumento. Mas, falando em funções, chegamos à segunda maior novidade
do R 4.1…
Funções anônimas: \(x)
Se você se acostumou com a notação de fórmulas do {purrr}
, então funções
anônimas não são nada de novo. Também conhecidas como lambdas, funções
anônimas não passam de funções que não precisam receber um nome, ou seja, podem
ser utilizadas pelo programa na hora de sua criação. No caso do {purrr}
isso
se dava através de uma gambiarra feita em cima das fórmulas (~.x
), mas, ainda
assim, isso era melhor do que a sintaxe bastante prolixa que o R básico exigia
(function(x) x
).
A nova sintaxe é, na minha opinião, bastante melhor que a estratégia do
{purrr}
. Apesar de ela ser um pouco mais extensa, ela funciona em todos os
lugares (não só no tidyverse), permite nomes arbitrários para os argumentos e
não bagunça a função do ~
. A nova função anônima é declarada com uma barra
oblÃqua para a esquerda seguida por todos os argumentos entre parênteses e o
código; essencialmente, é igual à notação antiga, mas function
vira \
. A
escolha do sÃmbolo \
também é ótima, pois é igual à de
outras linguagens e porque lembra
um λ (lambda) com a perna cortada. Para comparar todas as diferentes notações,
segue um breve exemplo (saÃdas suprimidas):
library(purrr)
# Sem função anônima
soma_um <- function(x) {
x + 1
}
map(1:10, soma_um)
# A notação antiga do {base} é extensa
map(1:10, function(x) x + 1)
# A notação do {purrr} força o .x
map(1:10, ~ .x + 1)
# A notação nova permite qualquer nome
map(1:10, \(n) n + 1)
# A notação nova funciona fora do tidyverse
lapply(1:10, \(x) x + 1)
# Para mais de 2 argumentos, o {purrr} muda
pmap(list(1:10, 11:20, 21:30), ~ ..1 + ..2 + ..3)
# A notação nova continua consistente
pmap(list(1:10, 11:20, 21:30), \(x, y, z) x + y + z)
De quebra, na minha opinião, também será muito mais fácil de ensinar o \(x)
do
que o ~.x
. A notação é intuitiva, consistente e funciona fora do tidyverse,
então, para mim, o novo lambda é até mais interessante do que o novo pipe!
Miscelânea
Para te poupar desse trabalho, eu li o NEWS da nova versão a fim de saber quais são as novidades mais interessantes do 4.1. Fora o novo pipe e o novo lambda, achei algumas coisas dignas de nota:
-
Usar
c()
para combinar fatores agora retorna um fator que também combina todos os nÃveis (de forma similar aoforcats::fct_c()
); -
apply()
agora tem um argumentosimplify
para desabilitar a simplificação de resultados; -
O novo utilitário
...names()
retorna os nomes dos argumentos passados via...
(possivelmente facilitando o trabalho do{tidyselect}
); -
As funções
URLencode()
eURLdecode()
agora funcionam com vetores de URIs; -
grep()
,sub()
,regexp()
, etc. ficaram mais rápidas para fatores longos com poucos nÃveis e -
duplicated()
eanyDuplicated()
agora são otimizados para vetores numéricos já ordenados via ALTREP.
Conclusão
Se você não consegue esperar para testar as novas funcionalidades, já é possÃvel baixar a versão beta do R 4.1 diretamente do site do R Project. O time do R Core apenas pede que você reporte quaisquer bugs detectados!
Para quem é mais paciente e prefere esperar o lançamento oficial na sua plataforma
de preferência, abra o seu RStudio, aperte CTRL + SHIFT + M com carinho e agradeça por
todas as aventuras patrocinadas pelo pipe. O pacote {magrittr}
continuará lá,
funcionando, mas cada vez menos relevante… Apesar de estarmos entrando em uma
nova fase do R, as lembranças e aprendizados do passado nunca irão embora.
%>%