Funções

  • O que são funções?
  • Dando nomes a funções
  • [seção bônus] Funções que recebem outras funções
    • map e reduce
  • [seção bônus] Funções anônimas
  • [seção bônus] Atribuição: let

O que são funções?

Você já viu algumas funções, como count, conj, first e rest. Toda a aritimética que fizemos usou funções também: +, -, *, e /. O que significa ser uma função então?

Uma função é um trecho distinto e independente de código que recebe alguns valores como entrada (chamados de argumentos ou parâmetros) e devolve um valor na saída.

Referência: Básicos de funções

  • count, conj, first
  • +, -, *, /
  • Um trecho de código que recebe valores e devolve um valor

Uma função com múltiplos argumentos

Funções também podem receber mais de um argumento. Vamos fazer uma função forward-right-with-len que recebe uma distância para frente, além da tartaruga.

(defn forward-right-with-len
  "Dado uma tartaruga e uma distância, ande para frente com a tartaruga e vire a sua cabeça"
  [turtle len]
  (forward turtle len)
  (right turtle 135))

(forward-right-with-len :trinity 90) ;=> {:trinity {:angle 135}}
(forward-right-with-len :neo 80)  ;=> {:neo {:angle 135}}

Dando nomes a funções

Nomes são símbolos

Nomes de função são símbolos, do mesmo jeito que os símbolos usados com o def quando atribuímos nomes a valores.

Símbolos devem começar com um caractere não numérico e podem conter caracteres alfanuméricos, além de *, +, !, -, _, e ?. Essa flexibilidade é importante para funções, pois existem alguns estilos de escrita que usamos.

Dois tipos de função

Clojure tem dois tipos de função:

  1. função que retorna um valor,
  2. função que retorna true ou false. O segundo tipo é chamado de predicado.
Exemplos de funções predicado

Em Clojure, = é uma função predicado, o que pode ser algo surpreendente. Além disso, como em muitas outras linguagens de programação, Clojure tem funções predicado para testar maior que, menor que, etc. A maioria dos predicados termina com ?, se começam com palavras.

  • =, not=
  • >, <, >=, <=
  • true?, false?, empty?, nil?, vector?, map?

[Seção bônus]

Funções que recebem outras funções

Algumas das funções mais poderosas que você pode usar com coleções recebem outras funções como argumento. Essa é uma das coisas mais mágicas sobre Clojure – e muitas outras linguagens de programação. É uma ideia complicada, e pode não fazer muito sentido à primeira vista. Vamos ver um exemplo e aprender mais sobre isso.

Referência: Funções de alta ordem

Função map

map é uma função que recebe outra função junto com uma coleção. Ela chama a função passada em cada um dos elementos da coleção, e devolve uma nova coleção com os resultados destas chamadas de função. É um conceito estranho, mas é a essência de Clojure e de programação funcional em geral.

(map inc [1 2 3]) ;=> (2 3 4)
(map (partial + 90) [0 30 60 90]) ;=> (90 120 150 180)

Referência: partial

Função reduce

Vamos ver outra função que recebe uma função. Essa é a reduce, e é usada para transformar coleções em um único valor.

reduce recebe os dois primeiros elementos da coleção passada e chama a função passada nesses dois elementos. Em seguida, chama a função novamente – dessa vez usando o resultado da chamada anterior da função como primeiro argumento e o próximo elemento da coleção como segundo. reduce vai fazer isso repetidas vezes até percorrer todos os elementos e chegar no fim da coleção.

(reduce + [30 60 90])       ;=> 180

[Seção bônus]

Funções anônimas

Funções sem nome

Até agora todas as funções que vimos tinham nomes, como + e str e reduce. No entanto, funções não precisam ter nome, assim como valores não precisam ter nomes. Chamamos funções sem nome de funções anônimas. Uma função anônima é criada com fn, assim:

Referência: Função anônima

(fn [s1 s2] (str s1 " " s2))

vs. funções que não são anônimas

Antes de prosseguir, você deve entender que você sempre está livre para dar um nome às suas funções. Não há nada de errado em fazer isso. No entanto, você vai ver código Clojure com funções anônimas, então deveria entender como elas funcionam.

(defn junta-com-espaco
  [s1 s2]
  (str s1 " " s2))

[Seção bônus]

Atribuição: let

Quando você cria funções, você pode quere dar nomes a valores para poder reutilizá-los ou deixar o seu código mais legível. Dentro de uma função, no entanto, você não deveria usar def, como você fez fora de uma função. Ao invés disso, você deveria usar uma expressão especial chamada let.

Atribuindo nomes a valores: let

Podemos atribuir um nome a um valor usando let da mesma forma que fizemos no def. Quando um nome está atribuído a um valor, esse nome é chamado de símbolo.

Referência: Atribuição let

(let [mangas 3
      laranjas 5]
  (+ mangas laranjas))
;=> 8

Voltar ao primeiro slide, ou ir para o índice do currículo.