Música Lambda (III): el cálculo y la música

Abstracción y aplicación
 
Hay un artículo que explica cómo podemos aplicar el cálculo lambda en la representación de procesos musicales: "Lambda Calculus and Music Calculi" de Yann Orlarey et al. (1994). En este escrito los autores muestran como un lenguaje formal diseñado para describir cierto dominio de la realidad, como la música, puede ser convertido en un lenguaje de programación agregándole las operaciones básicas del cálculo lambda: abstracción y aplicación.

Ya hemos visto que mediante abstracción, convierto una expresión en una función. Por ejemplo, puedo convertir el enunciado

El cubo es rojo

en una función proposicional; para ello simplemente cambiamos un término del enunciado por una variable:

x es rojo

De esta manera, por abstracción, obtenemos un predicado, una expresión que es verdadera de ciertas cosas. En este ejemplo "x es rojo" lo podríamos traducir como "lo que es rojo" o "la rojez", lo que los filósofos medievales llamaban un universal o lo que los lógicos modernos llamarían la definición de una clase. Esta es la operación que en el cálculo lambda llamamos abstracción, y lo expresamos de la siguiente manera:

λx.(R x)

donde:

R x := 'x es rojo'

Es decir, R es el predicado '... es rojo' y x es una variable. Si representamos el nombre "cubo" por una c, podríamos decir que obtenemos la expresión "λx.(R x)" como una abstracción de la expresión:

R c

que podemos leer como "el cubo rojo".

Hemos visto que la operación complementaria es la aplicación, que consiste en el reemplazo de las variables de una función (una generalización) por un objeto concreto al cual se aplica. Obtenemos una expresión concreta, particular, no general. La aplicación se expresa de la siguiente forma

M c

donde M es una función y c el objeto al que aplicamos la función. Podemos expresar la aplicación de la función que hemos construido por abstracción a un objeto:

[λx.(R x)] c

donde c es una constante que representa un objeto, en este caso el nombre "cubo". El resultado de la aplicación es:

R c

que, como hemos visto, significa "el cubo es rojo". Lo que hemos hecho es reemplazar la variable x ligada por el operador de abstracción lambda por el objeto c, al cual hemos aplicado nuestra función proposicional.


Música lambda

Veamos como funciona con la música. Supongamos que a cada nota de la escala diatónica la representamos con una letra, desde la a (la) hasta la g (sol). El sostenido lo representamos por #. El bemol por !. Por defecto cada nota dura una negra. Representamos un acorde como una lista, es decir, una secuencia de objetos separados por comas y encerrados entre corchetes. Por ejemplo, el acorde de do-mi-sol sería:

[c, e, g]

Por defecto todas las notas suenan teniendo como bases el la3. Para indicar secuencia o concatenación de eventos empleamos el símbolo ++; para indicar silencio escribimos r.

Supongamos que queremos repetir tres veces el acorde de do mayor (do, mi, sol), escribimos:
[c, e, g] ++ [c, e, g]  ++ [c, e, g]

Supongamos que queremos repetir tres veces el acorde de fa mayor en primera inversión (la, do, fa):
[a, c, f] ++ [a, c, f]  ++ [a, c, f]

Agreguemos,una expresión para asociar expresiones complejas a un nombre simple. Podemos entonces asociar a la expresión Cmayor el acorde de do mayor a Fmayor el acorde de fa mayor:

Cmayor = [c, e, g]
Fmayor = [ a, c, f

Como podemos observar, ambas expresiones tiene la misma estructura, así que podemos obtener una una función que generaliza la operación de repetir tres veces un acorde aplicando abstracción, reemplazando los acordes concretos por una variable:
λx.(x ++ x ++ x)
Aplicando esta función al acorde de do mayor obtenemos:
λx.(x ++ x ++ x) Cmayor
Cmayor ++ Cmayor ++ Cmayor

Aplicando la función al acorde de fa mayor obtenemos:
λx.(x ++ x ++ x) Fmayor
Fmayor ++ Fmayor  ++ mayor
Podemos también dar un nombre a la función que repite tres veces un evento:
rep3 = λx.(x ++ x ++ x)
Tenemos entonces:

rep3 Cmayor => Cmayor ++ Cmayor ++ Cmayor
rep3 Fmayor =>  Fmayor ++ Fmayor  ++ Fmayor

Escribamos ahora un canon: se trata de una melodía que suena al mismo tiempo que sí misma pero desplazada en el tiempo.

Tenemos la siguiente melodía:

mel = (c ++ d ++ e ++ c ++ c ++ d ++ e ++ c ++ e ++ f ++ g ++ e ++ f ++ g)

Ella puede ser superpuesta sobre sí misma si su repetición suena en el octavo tiempo después del comienzo de la original:

(r  ++ r ++ r ++ r ++ r  ++ r  ++ r  ++ r ++ c ++ d ++ e ++ c ++ c ++ d ++ e ++ c ++ e ++ f ++ g ++ e ++ f ++ g)

Obsérvese que la segunda melodía es igual a la primero, sólo que comienza ocho tiempos de negra después que la primera.

Podemos ser más económicos:
rest =  (r  ++ r ++ r ++ r ++ r  ++ r  ++ r  ++ r)
El canon sería entonces el resultado de superponer una melodía sobre sí misma, estando la superposición separada de la primera por un silencio de duración determinada:
[mel, (rest ++ mel)]
Haciendo abstracción obtenemos la función:
canon = λx. λy. [x, (y ++ x)]
donde x e y son variables que van a ser reemplazadas, x por una melodía e y por una secuencia de silencios:
λx. λy. [x, (y ++ x)]  mel rest =>
λy. [mel, (mel ++ y)]   rest  =>
[mel, (rest ++ mel)]

Si le damos un nombre a nuestra función para producir un canon, tenemos:
canon = λx. λy. [x, (y ++ x)]
canon mel rest => [mel, (rest ++ mel)]

Obsérvese que la aplicación opera de la siguiente forma: primero se aplica la función al primer argumento:
λx. λy. [x, (y ++ x)]  mel rest
y obtenemos una nueva función que se aplica al segundo argumento:
λy.y [mel, (rest ++ mel)]   rest
Lo que resulta en:
[mel, (rest ++ mel)]
Esta manera de evaluar las funciones se llama currificación, en honor a Haskell Curry. En nuestro caso, se produce una melodía que se repite al mismo tiempo que está sonando después de un silencio. Eso es un canon.

En general, podemos constatar acá como, desde el punto de vista computacional, el procedimiento de composición musical consiste fundamentalmente en dos procesos:
  • la proposición de bloques básicos, que no son realmente las notas, sino configuraciones definidas, identificables y fácilmente reconocibles cognitivamente que se elaboran empleando notas, tales como esos objetos melódicos que llamamos motivos o, en términos mayores, temas,
  • la aplicación de ciertas operaciones de transformación a esos bloques básicos. Esas operaciones pueden ser la imitación y la superposición, como en el caso del canon, pero hay otras, muy empleadas a lo largo de la historia de la música de occidente, tales como inversión, espejo, aumentación, disminución, transposición,
Tenemos entonces los objetos de un lenguaje funcional: objetos básicos y operaciones que se aplican a los objetos, que no son en realidad sino funciones, en el sentido matemático del término.

Lamentablemente, presentado de esa manera, no hay manera todavía de ver y escuchar cómo funciona el código ya que, aunque existen intérpretes para computadoras personales del cálculo lambda, no tenemos aún una extensión apropiada que traduzca lo que describimos usando el cálculo lambda a sonidos. En la actualidad, el lenguaje Haskell, a través del paquete Euterpea, sí nos permite hacer esto: describir procesos musicales y escucharlos. Esto lo veremos más adelante, ya que antes tenemos que ver lo principal, como asociar esos objetos musicales con tipos. Veremos que son los tipos aquello sobre lo cual operamos en términos lógicos, de manera que ofrecen una notación para especificar el proceso lógico que subyace a una obra.


Referencias

Church, Alonzo (1936): "An Unsolvable Problem of Elementary Number Theory". American Journal of Mathematics, Vol. 58, No. 2. (Apr., 1936), pp. 345-363

Orlarey, Jann, Dominique Fober, Stephane Letz and Mark Bilton (1994): "Lambda Calculus and Music Calculi". In International Computer Music Conference Proceedings, 1994, ppp. 243-250.


Comentarios