Criando variáveis e funções em Clojure
Tags: clojure, braziliandevs, beginners, programming
Published: 2023-05-15 12:00:00

O básico para começar a desenvolver em uma linguagem (funcional) é aprender a criar variáveis para armazenar os dados e funções para poder trabalhar com esses dados.

Vamos ver na prática como trabalhar com variáveis e criar funções, para isso vamos usar o REPL. Se ainda não sabe o que é, conheça [REPL - seu melhor amigo no mundo clojure](https://dev.to/afucher/repl-seu-melhor-amigo-no-mundo-clojure-3e56)

## Criando variáveis
Clojure preza pela imutabilidade, então quando criamos uma variável estamos definindo um símbolo com um valor.

```clojure
user=> (def foo 1)
#'user/foo
```
Nesse exemplo estamos definindo `foo` com o valor 1, o retorno é o nome completo do símbolo criado `#'user/foo`. Quando criamos, o Clojure cria na namespace atual, que no caso é `user`. Quando temos um arquivo, ele vai ter a própria namespace, e tudo criado lá dentro será pertencente aquela namespace. 
Agora podemos acessar o valor direto ou usá-lo passando para uma função:
```clojure
user=> foo
1
user=> (inc foo)
2
user=> foo
1
```
Notamos nesse exemplo que o valor de `foo` não mudou após a execução de `inc`. Isso é evidência a característica de imutabilidade que comentamos, ou seja, o valor não é alterado e sim o novo valor é retornado. 
Você pode estar pensando: 
> "podemos chamar o `def` novamente com o mesmo nome?"  

Sim, isso iria "redefinir". Mas não é recomendado fazer isso, então nem pense nisso 😅

## Criando funções
Da mesma maneira que usamos `def` para atribuir um valor simples, fazemos para criar uma função. Vamos criar uma função chamada `ola` que recebe um parâmetro `nome` e imprime `Olá <<nome>>`:

```clojure
(def ola
  (fn [nome]
    (println (str "Olá " nome))))
```
Estamos atribuindo a `ola` uma função, que definimos usando `fn`. Usamos `[]` para declarar os parâmetros que recebemos, e depois o corpo da função.
Agora podemos executar a função igual as outras que já vimos:
```clojure
user=> (ola "mundo")
Olá mundo
nil
```

### Retornando valores
No exemplo anterior, vimos que depois de imprimir a mensagem aparece `nil`, isso representa o retorno da nossa função. Em Clojure as funções retornam a última operação/valor.

```
user=> (defn soma2 [x] (+ x 2))
#'user/soma2
user=> (soma2 1)
3
```

### (def + fn)
Clojure criou uma maneira um pouco mais simplificada para a criação funções. 
Ao invés de escrever `def foo (fn []...)` para atribuir uma função, podemos utilizar `defn`. O exemplo anterior ficaria assim:
```clojure
(defn ola
  [nome]
  (println (str "Olá " nome)))
```

### Aridade
A aridade de uma função é a quantidade de parâmetros que ela recebe. Em Clojure podemos definir na mesma função múltiplas aridades, isso pode ser usado por exemplo para definir parâmetros opcionais ou valores default.
Vamos alterar a função `ola` para que quando for chamada sem nenhum parâmetro imprima "Ola mundão":
```clojure
(defn ola
  ([] (ola "mundão"))
  ([nome] (println (str "Olá " nome))))
```
Cada aridade é declarada envolta em `()` e declaramos da menor aridade para a maior.
Vamos executar novamente a função, não passando parâmetro e passando:
```
user=> (ola)
Olá mundão
nil
user=> (ola "mundo")
Olá mundo
nil
user=> (ola "mundo" "grande")
Execution error (ArityException) at user/eval2032 (REPL:1).
Wrong number of args (2) passed to: user/ola
```
Note que quando chamamos a função passando um número de argumentos que não existe, recebemos uma `ArityException`.

## Funções: de primeira classe
Em Clojure as funções são armazenadas e tratadas como os outros valores, portanto podem ser passadas como argumentos para outras funções 🤯
Para exemplificar, vamos criar uma função que receba o nome da pessoa e a forma como queremos cumprimentar:
```clojure
(defn cumprimentar
  [nome cumprimento] 
  (cumprimento nome))
```
E podemos executá-la:
```clojure
user=> (cumprimentar "Ariel" ola)
Olá Ariel
nil
```
Veja que a função `cumprimentar` recebe o `cumprimento` e executa passando o nome, que também veio como parâmetro, para ela.

## Docstring
Outra coisa importante é que quando declaramos uma função podemos criar junto uma documentação/descrição do que ela faz. Para isso basta passar antes dos parâmetros uma string com a descrição:
```clojure
(defn ola
  "Recebe um nome e devolve Olá <<nome>>"
  [nome]
  (println (str "Olá " nome)))
```
E agora, podemos usar a função `doc` que vimos no outro [post](https://dev.to/afucher/executando-funcoes-no-clojure-p4p) passando a nossa função:
```clojure
user=> (doc ola)
-------------------------
user/ola
([nome])
  Recebe um nome e devolve Olá <<nome>>
```
Muito legal né? 🤩

### Valores locais
Em Clojure podemos atribuir valores locais a nomes, dentro do escopo de funções, usando o `let`. Esses valores serão constantes, ou seja, não poderemos mais alterar ou redefinir.
Com o `let` você pode criar de uma vez 1 ou mais constantes, ele segue a seguinte estrutura:
```clojure
(let [nome valor
      nome valor]
  ;;Podemos utilizar dentro do escopo do let
)
```


Para exemplificar vamos alterar a função anterior para criar a string e armazenar localmente, e depois imprimir.

```clojure
(defn ola
  [nome]
  (let [mensagem (str "Ola " nome)]
    (println mensagem))) 
```

Criamos a `mensagem` com a string completa dentro do `let` e depois chamamos o `println`.

---
Espero que tenha gostado do conteúdo! Se sim, compartilhe, comente e/ou deixe uma reação. Isso ajuda a trazer visibilidade e saber que estão curtindo!
E se não gostou, comenta aí o que poderia melhorar! Quem sabe o próximo post você goste?

Abraços e até breve