1. Primeiros passos
2. Combine as funções
3. Uso parcial (currying)
4. Programação declarativa
5. Notação quintessencial
6. Imutabilidade e objetos
7. Imutabilidade e matrizes
8. Lentes
9. Conclusão
Este post é a sétima parte de uma série de artigos de programação funcional denominados Ramda Style Thinking.
Na sexta parte, falamos sobre como trabalhar com objetos JavaScript em um estilo funcional e imutável.
Neste post, falaremos sobre trabalhos semelhantes com matrizes.
Lendo elementos da matriz
Na sexta parte, aprendemos sobre as várias funções do Ramda para ler propriedades de objetos, como prop
, pick
e has
. O Ramda possui ainda mais métodos para ler elementos de array.
O equivalente de prop
para uma matriz é enésimo ; o equivalente para pick
é fatia e o equivalente para has
é contém . Vamos dar uma olhada neles.
const numbers = [10, 20, 30, 40, 50, 60] nth(3, numbers) // => 40 ( ) nth(-2, numbers) // => 50 ( ) slice(2, 5, numbers) // => [30, 40, 50] (. ) contains(20, numbers) // => true
A fatia pega dois índices e retorna uma sub-matriz que começa no primeiro índice (começando do zero) e inclui todos os elementos até o segundo índice, mas não incluindo o elemento desse índice.
Obter acesso ao primeiro e ao último elementos de uma matriz é bastante comum, portanto, o Ramda fornece funções curtas para esses casos, head e last . Ele também fornece funções para obter todos os elementos, exceto o primeiro ( cauda ), todos, exceto o último ( init ), os primeiros N elementos ( take (N) ) e os últimos N elementos ( takeLast (N) ). Vamos dar uma olhada neles em ação.
const numbers = [10, 20, 30, 40, 50, 60] head(numbers) // => 10 tail(numbers) // => [20, 30, 40, 50, 60] last(numbers) // => 60 init(numbers) // => [10, 20, 30, 40, 50] take(3, numbers) // => [10, 20, 30] takeLast(3, numbers) // => [40, 50, 60]
Adicionar, atualizar e excluir elementos da matriz
Estudando como trabalhar com objetos, aprendemos sobre as funções assoc
, dissoc
e omit
para adicionar, atualizar e excluir propriedades.
Como matrizes têm uma estrutura de dados ordenada, temos vários métodos que fazem o mesmo trabalho que assoc
para objetos. Os mais comuns são inserção e atualização , mas o Ramda também fornece métodos de acréscimo e pré- acréscimo para casos típicos de inclusão de elementos no início e no final de uma matriz. insert
, append
e acrescentar novos elementos à matriz; update
"substitui" um elemento específico na matriz por um novo valor.
Como você pode esperar de uma biblioteca funcional, todas essas funções retornam uma nova matriz com as alterações esperadas; a matriz original nunca muda.
const numbers = [10, 20, 30, 40, 50, 60] insert(3, 35, numbers) // => [10, 20, 30, 35, 40, 50, 60] append(70, numbers) // => [10, 20, 30, 40, 50, 60, 70] prepend(0, numbers) // => [0, 10, 20, 30, 40, 50, 60] update(1, 15, numbers) // => [10, 15, 30, 40, 50, 60]
Para combinar dois objetos em um, aprendemos anteriormente sobre o método de merge
. O Ramda também fornece um método concat para executar a mesma operação com matrizes.
const numbers = [10, 20, 30, 40, 50, 60] concat(numbers, [70, 80, 90]) // => [10, 20, 30, 40, 50, 60, 70, 80, 90]
Observe que a segunda matriz se juntou à primeira. Isso parece lógico ao usar esse método separadamente de outro código, mas, como na merge
, essa lógica pode não levar exatamente ao que seria de esperar se usássemos esse método em nosso pipeline. Achei útil escrever uma função auxiliar, concatAfter
: const concatAfter = flip(concat)
, para usá-la em meus pipelines.
O Ramda também oferece várias opções para excluir itens. remove remove itens por seu índice, enquanto sem remove por seu valor. Também existem métodos como drop e dropLast para casos típicos quando removemos elementos do início ou do fim de uma matriz.
const numbers = [10, 20, 30, 40, 50, 60] remove(2, 3, numbers) // => [10, 20, 60] without([30, 40, 50], numbers) // => [10, 20, 60] drop(3, numbers) // => [40, 50, 60] dropLast(3, numbers) // => [10, 20, 30]
Observe que remove
aceita um índice e uma quantia, enquanto a slice
aceita dois índices. Essa inconsistência pode ser confusa se você não souber.
Conversão de elemento
Como nos objetos, podemos desejar atualizar o elemento da matriz aplicando a função ao valor original.
const numbers = [10, 20, 30, 40, 50, 60] // 10 update(2, multiply(10, nth(2, numbers)), numbers) // => [10, 20, 300, 40, 50, 60]
Para simplificar esse caso típico, o Ramda fornece um método de ajuste que funciona como evolve
para objetos. Mas, ao contrário do evolve
, o adjust
funciona com apenas um elemento da matriz.
const numbers = [10, 20, 30, 40, 50, 60] // 10 adjust(multiply(10), 2, numbers)
Observe que os dois primeiros argumentos a serem adjust
são inversos ao compará-los com a update
. Isso pode ser uma fonte de erros, mas faz sentido quando você considera um aplicativo parcial. Você pode fazer o adjust(multiply(10))
por si mesmo e, posteriormente, decidir qual índice da matriz alterar usando-a.
Conclusão
Agora, temos ferramentas para trabalhar com matrizes e objetos em um estilo declarativo e imutável. Isso nos permite criar programas que consistem em pequenos blocos de construção funcionais, combinando funções que farão o que precisamos e tudo isso sem alterar todas as nossas estruturas de dados.
Seguinte
Aprendemos como ler, atualizar e transformar propriedades de objetos e elementos de matrizes. Ramda fornece outras ferramentas básicas para realizar essas operações, lentes. O próximo artigo sobre lentes nos mostrará como eles funcionam.