5.5 Funciones

# Funciones

Cuando comiences a escribir mucho código, desearás encontrar una
manera de organizar y estructurar todo para hacerlo más entendible.
Las funciones permiten hacer exactamente eso, permitiéndonos darle
nombre a muchas partes de nuestro código. Veamos:


## Definiendo Funciones

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

Aquí definimos una nueva función llamada `foo`. Lo hacemos con nuestro
viejo amigo el bloque de do/end y la palabra mágica `define` seguidos
del nombre que queremos darle a nuestra función. No necesitábamos
llamarla `foo`, podríamos haberla llamado cualquier cosa que quisiésemos,
tales como `bar`, `baz` o idealmente algo significativo para tí como
`main_section` o `lead_riff`.

Recuerda anteponer dos puntos `:` al nombre de la función que defines.


## Llamando las Funciones

Una vez hemos definido nuestra función, podemos llamarla simplemente
escribiendo su nombre:

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

foo

sleep 1

2.times do
  foo
end
```

Incluso podemos usar `foo` dentro de bloques de iteración o cualquier lugar
donde hayamos escrito `play` o `sample`. Esto nos da una fantástica manera 
de expresar y crear nuevas palabras significativas a usar en nuestras 
composiciones.

## Las funciones permanecen en memoria

Hasta ahora, cada vez que presionamos el botón de Ejecutar, Sonic Pi ha
comenzado de cero. Sólo conoce lo que está en el buffer actual. No puedes
referenciar código en otro buffer o hilo. sin embargo, las funciones cambian
eso. Cuando defines una función, Sonic Pi *recuerda*. Probemos borrando todo
el código en tu buffer y reemplazandolo por:


```
foo
```
Presiona el botón de Ejecutar y escucha. ¿Dónde se fue el código?¿cómo supo
Sonic Pi qué tocar? Sonic Pi recordó tu función, inclusive cuando la borraste
del buffer. Esta conducta sólo funciona con las funciones creadas con `define`
(y `defonce`).

## Funciones parametrizadas

Quizás te interese saber que al igual que podías pasar valores mínimos y máximos
con `rrand`, también puedes enseñar a tus funciones a aceptar argumentos. Miremos:

```
define :my_player do |n|
  play n
end

my_player 80
sleep 0.5
my_player 90
```

Esto no es tan excitante, pero ilustra el punto. Creamos nuestra propia versión 
de `play` llamada `my_player` y la cual está parametrizada.

Los parámetros deben ir después del `do` y `define` en el bloque `do/end`,
rodeado de postes verticales `|` y separados por comas `,`. Puedes usar cualquier
palabra para los nombres de los parámetros.

Lo mágico sucede dentro del bloque do/end del `define` . Puedes usar nombres de
parámetros como si fueran valores reales. En este ejemplo estoy tocando la nota
`n`.  Puedes considerar los parámetros como una especie de promesa de que cuando 
el código se ejecute, ellos serán reemplazados por los valores. Esto lo haces al
pasar un parámetro a la función, cuando la llamas. Yo lo hago con `my_player 80`
para tocar la nota 80. Dentro de la definición de la función `n` se reemplaza con
80, así `play n` se convierte en `play 80`. Cuando la llamo otra vez con
`my_player 90`, `n` es reemplazada por 90, así que `play n` se convierte en `play 90`.

Veamos un ejemplo más interesante:

``` 
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

```
Aquí usé `repeats` como si fuera un número para la línea de `repeats.times do`.
También usé `root` como si fuera un nombre de nota en mi llamada a `play`.

¡Nota cómo podemos utilizar algo muy expresivo y fácil de leer sólo con mover mucho
de nuestra lógica en el código!

