5.5 Funções

# Funções

Quando começares a escrever muito código, podes querer encontrar uma maneira de organizar e estruturar as coisas que forma elegante e de fácil compreensão. Funções são maneiras muito poderosas de conseguir isso. Elas dão-nos a habilidade de dar nome a uma serie de código. Vamos dar uma olhada.

## Definindo funções

```
define :foo do
  play 50
  sleep 1
  play 55
  sleep 2
end
```

Aqui definimos uma nova função chamada `foo`. Fazemos isso com o nosso amigo bloco do/end e a palavra magica `define` seguida pelo nome que queremos dar à nossa função. Não temos que a chamar `foo`, podemos chamar-lhe o que quisermos como `bar`, `baz` ou idealmente algo com sentido para ti como `secção_principal`ou `lead_riff`.

Lembra-te de acrescentar dois pontos `:` ao nome da tua função quando a definires.

## Chamando funções

Depois de definirmos a nossa função podemos a chamar escrevendo o seu nome:

```
define :foo do
  play 50
  sleep 1
  play 55
  sleep 0.5
end
foo
sleep 1
2.times do
  foo
end
```

Até podemos usar `foo` dentro de um bloco de iteração ou em qualquer lado que tenhamos escrito `play` ou `sample`. Isto dá-nos uma excelente maneira de nos expressar e cria palavras significativas para usar nas nossas composições.

## As funções são recordadas ao longo das execuções

Até agora, cada vez que carregas no botão Run, o Sonic Pi começa completamente do zero. Ele não sabe nada excepto o que está no buffer. Não podes referir código noutro buffer ou noutra thread. No entanto as funções mudam isso. Quando defines a função, o Sonic Pi *lembra-se* dela. Vamos experimentar. Apaga todo o código na teu buffer e substitui por:

```
foo
```

Carrega no botão Run - ouve a tua função a tocar. Onde foi o código? Como é que o Sonic Pi sabe o que tocar? O Sonic Pi lembra-se da tua função - assim mesmo que apagues do buffer, ele lembra-se do que escreveste. Este comportamento apenas funciona com funções criadas usando o `define` (e `defonce`).

## Funções parametrizadas

Podes estar interessado em saber que tal como tu podes passar valores mínimos e máximos a `rrand`, tu também podes ensinar as tuas funções a aceitar argumentos. Vamos dar uma olhada:

```
define :my_player do |n|
  play n
end
my_player 80
sleep 0.5
my_player 90
```

Isto não é muito excitante, mas ilustra o ponto. Criamos a nossa versão de `play`chamada `my_player`que é parametrizada.

Os parâmetros devem vir a seguir ao `do` do bloco `define`, rodeados pela barra vertical `|` e separados por virgulas `,`. Podes usar qualquer palavra para o nome dos parâmetros.

A magia acontece dentro do bloco `define`. Podes querer usar nomes de parâmetros como se fossem valores reais. Neste exemplo estou a tocar a nota `n`. Podes considerar que os parâmetros são uma espécie de promessa que quando o código corre serão substituídos por valores actuais. Fazes isso passando um parâmetro às função quando a chamas. Eu faço isso com `my_player 80` para tocar a nota 80. Dentro da definição da função, `n`é então substituído por 80, assim `play n`fica `play 80`. Quando a chamas novamente com `my_play 90`, o `n`é substituído por 90 e `play n`fica `play 90`.

Vamos ver um exemplo mais interessante:

```
define :chord_player do |root, repeats| 
  repeats.times do
    play chord(root, :minor), release: 0.3
    sleep 0.5
  end
end
chord_player :e3, 2
sleep 0.5
chord_player :a3, 3
chord_player :g3, 4
sleep 0.5
chord_player :e3, 3
```

Onde usei `repeat` como se fosse um número na linha `repeat.times do`. Também usei `root` como se fosse o nome de uma nota na minha chamada a `play`.

Vê como podemos escrever algo muito expressivo e facil à leitura movendo muito da nossa lógica para uma função!
