O Problema Que os Pipes Resolvem
Um pipe pega o valor antes dele e o alimenta na chamada de função depois dele - x |> f() significa f(x). Isso parece uma reescrita trivial até você encadear três ou quatro etapas. Sem um pipe, transformações de várias etapas se aninham, e chamadas aninhadas se leem de trás para frente: a primeira coisa que acontece fica na posição mais interna.
Para ler round(sqrt(x), 1) você começa no meio (x), vai para fora (sqrt, depois round) e ainda tem que acompanhar qual , 1) final pertence a qual chamada. Com três níveis isso é irritante; com cinco níveis, com verbos de data frame e vários argumentos cada, é genuinamente difícil de seguir. A alternativa a que as pessoas recorrem - salvar cada etapa intermediária em tmp1, tmp2, tmp3 - polui o workspace com nomes de que ninguém precisa.
Um pipe reescreve a cadeia na ordem em que as etapas realmente acontecem: pegue x, então tire a raiz quadrada, então arredonde.
O Pipe Nativo |>
Desde o R 4.1, o pipe está embutido na própria linguagem - nenhum pacote necessário. |> insere o valor anterior como primeiro argumento da próxima chamada:
c(1, 4, 9, 16) |> sqrt() |> round(1) é exatamente round(sqrt(c(1, 4, 9, 16)), 1) - o R literalmente reescreve um no outro durante a análise sintática, então não há custo algum em tempo de execução. Mas agora o código se lê como uma receita, de cima para baixo: os dados, depois cada transformação em ordem. Isso funciona com qualquer função, não só com ferramentas de dados - mtcars |> head(3) é R base puro de ponta a ponta.
Repare como os pipes combinam bem com funções cujo primeiro parâmetro é "os dados": head, sort, unique, summary e todo verbo do dplyr são projetados assim, e é por isso que pipelines parecem tão naturais no R.
As Regras do |>
O pipe nativo é deliberadamente rígido. Três regras cobrem quase tudo:
1. A próxima etapa precisa ser uma chamada, com parênteses. x |> sqrt é um erro de sintaxe; você precisa escrever x |> sqrt():
c(1, 4, 9) |> sqrt # Error: The pipe operator requires a function call as RHS
c(1, 4, 9) |> sqrt() # correct
2. O valor cai na posição do primeiro argumento. Argumentos extras que você escrever permanecem no lugar, depois dele - x |> round(1) é round(x, 1).
3. Para cair em qualquer outro lugar, use o placeholder _ com um argumento nomeado (R 4.2+). Caso clássico: lm recebe uma fórmula primeiro e os dados depois, então canalizar um data frame para ela exige data = _:
O _ pode aparecer uma vez, e apenas como argumento nomeado. Quando isso é restritivo demais, canalize para uma função anônima - ela pode colocar o valor onde quiser:
O lambda é envolvido em parênteses e depois chamado com () - isso mantém a regra 1 satisfeita. Se você se pegar fazendo isso com frequência em um pipeline, aquela etapa provavelmente quer virar uma função nomeada.
O Pipe do magrittr %>%
Antes de a linguagem ter um pipe, o pacote magrittr fornecia um, e %>% virou a assinatura do código tidyverse - carregar o dplyr te dá ele automaticamente. Você vai vê-lo em praticamente todo tutorial de dplyr e script escrito na última década:
library(dplyr)
mtcars %>%
filter(mpg > 30) %>%
select(mpg, wt)
Como %>% vem de um pacote, esses exemplos não são executáveis em uma sessão R pura - Error: could not find function "%>%" é exatamente o que você recebe se esquecer o library(dplyr) (ou library(magrittr)).
O comportamento no caso comum é idêntico ao de |>: alimentar o valor anterior no primeiro argumento da próxima chamada. Mas o magrittr é mais permissivo:
c(1, 4, 9) %>% sqrt # bare function name - no parentheses needed
mtcars %>% lm(mpg ~ wt, data = .) # . placeholder, usable anywhere
c(-2, 3) %>% { max(abs(.)) } # . can even appear several times, in nested calls
|> vs %>%: As Diferenças Que Importam
Para um pipeline de primeiro argumento - que é a esmagadora maioria do código real - os dois são intercambiáveis. As diferenças moram nas bordas:
- Disponibilidade:
|>é R base 4.1+;%>%precisa do magrittr (normalmente via dplyr). - Parênteses:
|>exigesqrt();%>%aceitasqrtsem parênteses. - Placeholder:
|>usa_, uma vez, apenas como argumento nomeado (4.2+);%>%usa., em qualquer lugar, quantas vezes quiser, inclusive dentro de chamadas aninhadas. - Velocidade:
|>é reescrito em tempo de análise para a chamada aninhada - custo zero.%>%é uma chamada de função comum, com um pequeno custo (na prática desprezível).
Nada aqui torna %>% errado - ele é testado em batalha e um pouco mais flexível. Mas tudo que ele faz além do |> pode ser feito com um lambda, e o pipe base não precisa de dependência.
Qual Você Deve Usar?
Para código novo: use |>. Ele faz parte da linguagem, funciona em qualquer lugar onde o R 4.1+ rode, não precisa de pacote, e sua rigidez se lê como um recurso - pipelines permanecem simples ou são refatorados em funções nomeadas.
Mas você precisa conseguir ler %>% fluentemente, porque bases de código tidyverse, respostas do Stack Overflow e a maioria dos livros de R escritos desde 2014 estão cheios dele. Times com um estilo dplyr já estabelecido muitas vezes mantêm %>% por consistência, e essa é uma decisão razoável - a pior escolha é misturar os dois operadores em um mesmo arquivo. Independentemente do que você escrever, uma convenção vale para ambos: em pipelines longos, coloque cada etapa em sua própria linha com o pipe no fim da linha, para que a receita se leia como uma lista de passos.
O mesmo bom senso da família apply se aplica aqui: pipes são para transformações lineares, passo após passo. Quando um cálculo se ramifica ou precisa de resultados intermediários duas vezes, atribua uma variável bem nomeada em vez de forçar tudo por uma única cadeia.
O Que Você Leva Daqui
- Um pipe alimenta o valor anterior na próxima chamada:
x |> f() |> g()ég(f(x)), escrito na ordem em que acontece. |>é R base (4.1+): exige parênteses, mira no primeiro argumento, placeholder_com argumento nomeado (4.2+).%>%é magrittr/tidyverse: nomes sem parênteses são permitidos, placeholder.em qualquer lugar - mas precisa de um pacote.- Prefira
|>em código novo; leia%>%em todo o resto sem pestanejar. - Pipes servem a receitas lineares; lógica com ramificações merece variáveis nomeadas.
A seguir: pacotes - de onde %>%, dplyr e as outras 20 mil extensões do R realmente vêm.
Perguntas frequentes
O que %>% significa no R?
%>% é o pipe do magrittr: ele pega o valor antes dele e o alimenta como primeiro argumento da chamada depois dele, então x %>% f() %>% g() significa g(f(x)). Ele vem do pacote magrittr e é carregado automaticamente com o dplyr e o tidyverse - não faz parte do R base.
Preciso de um pacote para usar |> no R?
Não. |> é o pipe nativo, embutido no R base desde a versão 4.1 - ele funciona em uma sessão R comum, sem nada instalado. %>% é o que precisa de um pacote (magrittr, ou qualquer coisa que o reexporte, como o dplyr).
Qual é a diferença entre |> e %>% no R?
Ambos alimentam o valor anterior na próxima chamada. |> é do R base, exige parênteses explícitos (x |> sqrt()) e usa o placeholder _ apenas com um argumento nomeado. %>% precisa do magrittr, aceita nomes de função sem parênteses (x %>% sqrt) e seu placeholder . pode ir a qualquer lugar, quantas vezes quiser. O comportamento é idêntico no caso comum do primeiro argumento.