Clojure: estrutura de dados

Lucas Oliveira
April 25th, 2020 · 2 min read

Nesse post veremos as estruturas de dados básicas de clojure, algumas diferenças e aplicações.

Clojure conta com 4 estruturas principais: Vetores, Listas, Sets e Mapas. Antes de entrar nelas, precisamos passar primeiro por Collections.

Collections

Na orientação a objeto, nós programadores conseguimos criar tipos diferentes dos habituais e também conseguimos definir as operações disponíveis para esses tipos. Porém, quando criamos novos tipos (e classes) específicos para o nosso negócio, acabamos tendo sempre que empregar tempo em definir nomes sugestivos o suficiente para essas estruturas.

Também precisamos criar funções, interfaces e estruturas mais genéricas e tudo isso representa em um maior volume de código. Esse volume maior de código representa mais espaço para o surgimento de comportamentos não previstos (BUGS).

Agora enquanto a orientação a objetos precisa de tipos que definam as características daquele dado, a programação funcional e, no nosso caso, clojure, tenta limitar o uso a quatro estruturas básicas. Essas quatro estruturas implementam a mesma abstração e, por isso, contam com algumas funções em comum. Ok, mas o que isso significa? Bom, significa que independente da estrutura que você escolher, terá algumas funções básicas em comum (ex: count, conj, seq).

Vetores

Vetores são um tipo de collection similares aos arrays de outras linguagens. Eles mantém a ordem de inserção, permitem que valores duplicados existam e seus valores são acessados pelo index (começando pelo 0). Formas de criar um Vetor:

1user=> [7 9 2 1 4 5]
2//[7 9 2 1 4 5]
3
4
5user=> (vector 14 11 77)
6//[14 11 77]

Outra característica interessante dos vetores é que eles podem ter tipos diferentes de valores:

1user=> [1 "olá" :chave "bla" {:chave "valor"}]
2//[1 "olá" :chave "bla" {:chave "valor"}]
3
4user=> (def vetor ["olá" 1 :chave "bla" {:chave "valor"}])
5//#'user/vetor
6
7user=> (vetor 0)
8//"olá"
9
10user=> (vetor 1)
11//1
12
13user=> (vetor 2)
14//:chave
15
16user=> (vetor 3)
17//"bla"
18
19user=> (vetor 4)
20//{:chave "valor"}

São usadas quando é necessário garantir que o primeiro dado a chegar seja o último a sair (FIFO, filas e tal).

1user=> (conj vetor 777)
2//[1 "abc" {:key "value"} 777]
3
4user=> (pop vetor)
5//[1 "abc"]

Listas

Listas são similares aos vetores, porém os itens são adicionados ao começo da collection. Também não são tão performáticos quanto os vetores quando precisamos acessar posições específicas.

Formas de criar uma Lista:

1user=> '("a" 1 :chave)
2//("a" 1 :chave)
3
4
5user=> (list 1 "abc" {:key "value"})
6//(1 "abc" {:key "value"})

São usadas quando é necessário garantir que o último dado a chegar seja o primeiro a sair (LIFO, pilhas e tal).

1user=> (conj lista 777)
2//(777 1 "abc" {:key "value"})
3
4user=> (pop lista)
5//("abc" {:key "value"})

Sets

O Set é uma coleção com valores únicos. Ou seja, valores repetidos não são inseridos novamente (inclusive um erro é levantado). Os Sets dividem em HashSet e SortedSet.

Formas de criar um HashSet:

1user=> #{1 2 3 4 5}
2//#{1 4 3 2 5}
3
4
5user=> (hash-set 6 7 8)
6//#{7 6 8}

O HashSet, assim como o HashMap é uma estrutura onde os valores inseridos recebem um h a s h, que otimiza a velocidade de acesso porém não mantém a ordem em que os registros foram inseridos, como vimos no último exemplo.

Para os casos onde é necessário garantir a ordem de inserção (e abrir mão de um pouco de velocidade de acesso), podemos usar o SortedSet:

1user=> (sorted-set 6 7 8)
2//#{6 7 8}

Maps

Maps ou Mapas são a estrutura chave-valor que possuímos em clojure. Assim como a estrutura Set, o Map também não permite registros duplicados. Imagino que pelo menos na forma e funcionamento seja similar ao objeto do javascript e dicionário do python.

Formas de criar um HashMap:

1user=> {:chave1 "valor1", :chave2 "valor2"}
2//{:chave1 "valor1", :chave2 "valor2"}
3
4
5user=> (hash-map :chave1 "valor1" :chave2 "valor2")
6//{:chave2 "valor2", :chave1 "valor1"}

Assim como o Set, há uma função (sorted-map) para ser usada caso haja necessidade de garantir que a ordem de inserção:

1user=> (sorted-map :chave1 "valor1" :chave2 "valor2")
2//{:chave1 "valor1", :chave2 "valor2"}

Acredito que por ora seja isso. Espero complementar esse artigo com mais detalhes futuramente. Um componente para o terminal também seria bem legal.


Abraços~

More articles from Lucas Oliveira

Clojure: tipos de dados

Aqui vou escrever um pouco sobre o que espero estudar e fazer durante as férias.

April 25th, 2020 · 1 min read

É férias que fala, né?

Aqui vou escrever um pouco sobre o que espero estudar e fazer durante as férias.

April 24th, 2020 · 1 min read