Entendendo Scala Sequence Comprehensions
Neste post explicarei a “mágica” por trás da sintaxe de sequence comprehensions em Scala..
1 2 3 4 5 6 |
|
A sintaxe lembra um SELECT...JOIN
em SQL onde a cláusula WHERE
requer que
x
e y
sejam pares. O resultado da avaliação da expressão for
acima é a
lista de todos os pares de números pares entre 1 e 6.
1
|
|
A mesma lista poderia ser definida de outra forma.
1 2 3 4 5 |
|
Sequence comprehensions são traduzidas para expressões equivalentes em termos
de flatMap
, map
, e withFilter
que são métodos definidos em todas as
Collections da linguagem Scala. Como exemplo, nesse post, estou usando apenas
a
List
, mas qualquer classe que defina flatMap
, map
e withFilter
pode
ser usada dentro de expressões for
como essas.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
|
Para entendimento desse post, pode-se entender withFilter
como sendo
indêntico ao método filter
. A diferença é que em vez de alocar uma nova
lista, withFilter
passa a lista e o predicado para a criação de uma instância
de WithFilter
. WithFilter
define map
, flatMap
, filter
,
withFilter
… mas restringe a aplicação dessas funções apenas aos valores que
satisfazem ao predicado da chamada a withFilter
, comportando-se exatamente
como uma List
resultante da aplicação de filter
.
1 2 3 4 5 6 7 8 9 |
|
Nesse exemplo, flatMap
transforma uma lista de linhas de um texto em uma
lista de palavras de um texto. Para isso, basta prover a flatMap
uma função
que transforma uma linha em uma lista de palavras. flatMap
aplicará essa
função a cada linha e concatenará as listas resultantes para produzir o
resultado final.
Após entender as definições de withFilter
, flatMap
e map
, vamos às regras
de tradução de sequence comprehensions.
1 for simples
1 2 3 4 5 |
|
Em sua forma mais simples, um for
é simplesmente um map.
1 2 3 4 5 6 |
|
2 for com filtro
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
if
s são traduzidos para chamadas a withFilter
.
3 for com sequência de geradores
1 2 3 4 5 6 |
|
Quando há mais de um gerador, flatMap
é usado. Você pode entender a sequência
de geradores como várias chamadas aninhadas a flatMap
(regra 3) e filtros
quando necessário, que produzem uma única sequência que servirá para a
aplicação de map
ao final. A função passada para map
é construída a partir
da expressão após a palavra-chave yield
.
Juntando tudo
Vamos traduzir as expressões for
apresentadas no início do post.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
|
A primeira forma tem apenas um filtro (equivalente ao if x % 2 == 0 && y % 2 == 0
).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
|
A segunda forma tem dois filtros (um para testar a paridade de x
e outro para
testar a paridade de y
).