• No se han encontrado resultados

Las Raices de Lisp

N/A
N/A
Protected

Academic year: 2021

Share "Las Raices de Lisp"

Copied!
13
0
0

Texto completo

(1)

Las Raíces de Lisp

Las Raíces de Lisp

PAUL GRAHAM

PAUL GRAHAM

 Borrador, Enero 18, 2002  Borrador, Enero 18, 2002

En 1960,

En 1960, John McCarthyJohn McCarthy publicó un notable artículo en el que hizo publicó un notable artículo en el que hizo por la programación algopor la programación algo  parecido a lo que Eucl

 parecido a lo que Euclides hizo por la geometríaides hizo por la geometría..11 Demostró cómo, dado un puñado deDemostró cómo, dado un puñado de operadores simples y una notación para funciones, se

operadores simples y una notación para funciones, se puede construir un lenguaje depuede construir un lenguaje de  programación. Llamó a

 programación. Llamó a este lenguaje Lisp, por "List Proceste lenguaje Lisp, por "List Processing", debido a que una de susessing", debido a que una de sus  principales ideas era usar

 principales ideas era usar una estructura de datos simple una estructura de datos simple llamadallamada list list tanto para el código comotanto para el código como

 para los datos.  para los datos.

Vale la pena comprender lo que McCarthy descubrió, no

Vale la pena comprender lo que McCarthy descubrió, no sólo como un hito en sólo como un hito en la historia de lasla historia de las computadoras, sino como un modelo para lo

computadoras, sino como un modelo para lo que la programación tiende a convertirse enque la programación tiende a convertirse en nuestro propio tiempo. Me parece que hasta la

nuestro propio tiempo. Me parece que hasta la fecha ha habido dos modelos de fecha ha habido dos modelos de programaciónprogramación limpios y consistentes: el modelo C y

limpios y consistentes: el modelo C y el modelo Lisp. Estos dos el modelo Lisp. Estos dos se asemejan a puntos elevadosse asemejan a puntos elevados sobre el terreno, con tierras bajas pantanosas entre

sobre el terreno, con tierras bajas pantanosas entre ellos. Conforme las computadoras se hanellos. Conforme las computadoras se han vuelto más potentes, los nuevos lenguajes en

vuelto más potentes, los nuevos lenguajes en desarrollo se han estadodesarrollo se han estado moviendo de maneramoviendo de manera

continua

continua hacia el modelo de Lisp. Una receta popular para hacia el modelo de Lisp. Una receta popular para los nuevos lenguajes delos nuevos lenguajes de  programación en los últim

 programación en los últimos 20 años ha sido la de tomar el os 20 años ha sido la de tomar el modelo C de la informátimodelo C de la informática yca y agregarle, poco a poco, partes tomadas del modelo de

agregarle, poco a poco, partes tomadas del modelo de Lisp, tales como la escritura en tiempo deLisp, tales como la escritura en tiempo de ejecución y la recolección de basura.

ejecución y la recolección de basura.

En este artículo trataré de explicar en los términos más

En este artículo trataré de explicar en los términos más simples posibles lo que McCarthysimples posibles lo que McCarthy descubrió. La idea no es sólo

descubrió. La idea no es sólo conocer el interesante resultado teórico descubierto hace cuarentaconocer el interesante resultado teórico descubierto hace cuarenta años, sino demostrar hacia dónde se

años, sino demostrar hacia dónde se dirigen los lenguajes. Lo inusual de Lisp dirigen los lenguajes. Lo inusual de Lisp —de hecho, la—de hecho, la característica distintiva de Lisp— es que se puede escribir a

característica distintiva de Lisp— es que se puede escribir a sí mismo. Para comprender lo quesí mismo. Para comprender lo que McCarthy quiso decir con esto, volveremos sobre

McCarthy quiso decir con esto, volveremos sobre sus pasos, con ssus pasos, con su notación matemáticau notación matemática traducida a código corriente de Common Lisp.

traducida a código corriente de Common Lisp.

1 Siete Operadores Primarios 1 Siete Operadores Primarios Para empezar, definimos una

Para empezar, definimos una expresiónexpresión. Una expresión es ya sea un. Una expresión es ya sea un atomatom, que es una secuencia, que es una secuencia

de letras (por ejemplo:

de letras (por ejemplo: foofoo) o una) o una listalista de cero o más de cero o más expresiones, separadas por espacio enexpresiones, separadas por espacio en

 blanco y encerradas por pa

 blanco y encerradas por paréntesis. Estas son algunas expresiones:réntesis. Estas son algunas expresiones:

foo foo () () (foo) (foo) (foo bar) (foo bar) (a b (c) d) (a b (c) d)

La ultima expresión es una lista de

La ultima expresión es una lista de cuatro elementos, la tercera de las cuales es en cuatro elementos, la tercera de las cuales es en si misma unasi misma una lista de un elemento.

lista de un elemento.

  11

“Recursive Functions of Symbolic Expressions and Their Computation byMachine, Part I”

(2)

En aritmética la expresión 1+1 tiene un valor de 2. Las expresiones de Lisp validas también tienen valores. Si una expresión e arroja un valor v decimos que e devuelve v. Nuestro siguiente

 paso es definir qué tipos de expresiones puede haber, y qué valor devuelve cada una. Si una expresión es una lista, llamamos al primer elemento el operador y a los elementos

restantes los argumentos. Vamos a definir siete operadores primarios (en el sentido de los

axiomas): quote, atom, eq, car, cdr, cons, y cond.

1. (quote  x) devuelve x. Por facilidad de lectura abreviaremos

(quote  x) como  x′ . >(quote a) a > ′a a > (quote (a b c)) (a b c)

2. (atom  x) devuelve el atom t si el valor de xes un atom o la lista

vacía. De lo contrario regresa (). En Lisp por lo general usamos el atom t para

representar verdadero, y la lista vacía para representar falso.

> (atom ′a) t >(atom ′(a b c)) () > (atom ′()) t

Ahora que tenemos un operador cuyo argumento es evaluado podemos mostrar para qué sirve quote. Al poner quote a una lista la protegemos de ser evaluada. Una

lista sin quote que se da como argumento a un operador como atom es tratada

como código:

> (atom (atom ′a))

t

mientras que una lista a la que se le aplicó quote es tratada como una simple lista,

en este caso, una lista de dos elementos:

> (atom ′(atom ′a))

()

Esto es igual a la manera en que usamos las comillas en Inglés. Cambridge es un  pueblo en Massachusetts que tiene cerca de 90,000 personas. “Cambridge” es una  palabra que contiene nueve letras.

(3)

Quote puede parecer un concepto extraño, porque muy pocos otros lenguajes tienen algo parecido. Esta estrechamente ligada a una de las características más distintivas de Lisp: el código y los datos se componen de las mismas estructuras de datos, y el operador quote es la manera en que distinguimos entre ellos.

3. (eq  x y) devuelve t si los valores de x y y son el mismo atom o si

ambos son la lista vacía, de otra manera devuelve (). > (eq ′a ′a) t > (eq ′a ′b) () > (eq ′() ′()) t

4. (car  x) espera que el valor de x sea una lista, y devuelve su primer elemento

> (car ′(a b c))

a

5. (cdr  x) espera que el valor de  x sea una lista, y devuelve todo

después del primer elemento.

> (cdr ′(a b c))

(b c)

6. (cons  x y) espera que el valor de y sea una lista, y devuelve una

lista que contiene el valor de x seguido por los elementos del valor de y.

> (cons 'a '(b c)) (a b c)

> (cons 'a (cons 'b (cons 'c '()))) (a b c)

> (car (cons 'a '(b c))) a

> (cdr (cons 'a '(b c))) (b c)

7. (cond ( p1 e1)...( pn en)) es evaluado como sigue. Las expresiones p son

evaluadas en orden hasta que una devuelve t. Cuando se encuentra una, el valor de

la correspondiente expresión e es devuelto como el valor de la totalidad de la

expresión cond.

> (cond ((eq 'a 'b) 'first) ((atom 'a) 'second)) second

(4)

En cinco de nuestros siete operadores primarios, los argumentos son siempre evaluados cuando una expresión que empieza con ese operador es evaluada.2Llamaremos a un operador de ese tipo una función.

2 Denotando Funciones

Enseguida definimos una notación para describir funciones. Una función es expresada como

(lambda ( p1... pn) e)donde p1... pn son atoms (llamados parámetros) y e es una expresión. A una expresión cuyo primer elemento es tal expresión

((lambda ( p1... pn) e) a1...an)

se le denomina llamada a función y su valor se calcula de la siguiente manera. Cada expresión aies evaluada. Luego ees evaluada. Durante la evaluación de e, el valor de cualquier 

ocurrencia de una de las pi es el valor de la ai correspondiente en la más reciente llamada a

función.

> ((lambda (x) (cons x '(b))) 'a) (a b)

> ((lambda (x y) (cons x (cdr y))) 'z

'(a b c)) (z b c)

Si una expresión tiene un atom f como su primer elemento que no sea uno de los operadores

 primarios

( f ai...an)

y el valor de f es una función (lambda ( p1... pn) e) entonces el valor de la expresión es

el valor de

((lambda ( p1... pn) e) a1...an)

En otras palabras, los parámetros pueden ser usados como operadores en expresiones lo mismo que como argumentos:

> ((lambda (f) (f '(b c))) '(lambda (x) (cons 'a x))) (a b c)

Hay otra notación para funciones que habilita la función para referirse a si misma, dándonos  por lo tanto una manera conveniente para definir funciones recursivas.3



2Las expresiones que empiezan con los otros dos operadores,quoteycond, son evaluados de manera diferente. Cuando

una expresiónquotees evaluada, su argumento no es evaluado, sino que sólo es devuelto como el valor total de la

expresiónquote. Y en una expresióncondvalida, solo una ruta de subexpresiones en forma de L será evaluada. 3Lógicamente, no necesitamos definir una nueva notación para esto. Podemos definir funciones recursivas en nuestra

notación existente utilizando una función de las funciones denominada el combinador Y. Puede que McCarthy no supiera del combinador Y cuando escribió este documento; de cualquier manera, la notaciónlabeles más fácil de leer.

(5)

La notación

(label  f  (lambda ( p1... pn) e))

denota una función que se comporta como (lambda ( p1... pn) e), con la propiedad

adicional que una ocurrencia de f dentro de eevaluara a la expresión label, como si f fuera un

 parámetro de la función.

Supón que queremos definir una función (subst  x y z ), que toma una expresión x, un atom  y, y una lista z , y devuelve una lista como z  pero con cada instancia de y (a cualquier nivel de

anidamiento) en z reemplazada por  x.

>(subst 'm 'b '(a b (a b c) d)) (a m (a m c) d)

Podemos denotar esta función como

(label subst (lambda (x y z) (cond ((atom z)

(cond ((eq z y) x) ('t z)))

('t (cons (subst x y (car z))

(subst x y (cdr z)))))))

Abreviaremos f =(label  f  (lambda ( p1... pn) e)) como

(defun  f  ( p1... pn) e)  por tanto (defun subst (x y z) (cond ((atom z) (cond ((eq z y) x) ('t z)))

('t (cons (subst x y (car z))

(subst x y (cdr z))))))

Incidentalmente, aquí vemos como obtener una cláusula por defecto en una expresión cond.

Una cláusula cuyo primer elemento es ′t siempre tendrá éxito. Así

(cond ( x y) (′t  z ))

es equivalente a lo que podríamos escribir en un lenguaje con sintaxis como

if  x then  y else  z 

3 Algunas Funciones

Ahora que tenemos una manera de expresar funciones, definimos unas nuevas en función de nuestros siete operadores primarios. Primero será conveniente introducir algunas abreviaciones

(6)

 para patrones comunes. Usaremos c xr, donde x es una secuencia de as o ds, como una

abreviación para la correspondiente composición de car y cdr. Así por ejemplo (cadr e)

es una abreviación para (car (cdr e)), que devuelve el segundo elemento de e.

> (cadr '((a b) (c d) e)) (c d)

> (caddr '((a b) (c d) e)) e

> (cdar '((a b) (c d) e)) (b)

Asimismo, utilizaremos (list e1...en) para

(cons e1 ... (cons en ′()) ... ).

> (cons 'a (cons 'b (cons 'c '()))) (a b c)

> (list 'a 'b 'c) (a b c)

Ahora definimos algunas funciones nuevas. Cambié los nombres de estas funciones agregando  puntos al final. Esto distingue las funciones primarias de aquellas definidas en función de estas,

y también evita conflictos con funciones existentes de Common Lisp. 1. (null.  x) comprueba si su argumento es la lista vacía.

(defun null. (x) (eq x '())) > (null. 'a) () > (null. '()) t

2. (and.  x  y) devuelve t si ambos de sus argumentos lo hacen y de lo contrario (). (defun and. (x y)

(cond (x (cond (y 't) ('t '()))) ('t '())))

> (and. (atom 'a) (eq 'a 'a)) t

> (and. (atom 'a) (eq 'a 'b)) ()

3. (not.  x) devuelve t si su argumento regresa (), y ()si su argumento devuelve t.

(7)

(defun not. (x) (cond (x '())

('t 't))) > (not. (eq 'a 'a)) ()

> (not. (eq 'a 'b)) t

4. (append.  x y)toma dos listas y devuelve su concatenación. (defun append. (x y)

(cond ((null. x) y)

('t (cons (car x) (append. (cdr x) y))))) > (append. '(a b) '(c d))

(a b c d)

> (append. '() '(c d)) (c d)

5. (pair.  x y)toma dos listas de la misma longitud y devuelve una lista de listas de

dos elementos que contienen pares sucesivos de un elemento de cada una.

(defun pair. (x y)

(cond ((and. (null. x) (null. y)) '())

((and. (not. (atom x)) (not. (atom y))) (cons (list (car x) (car y))

(pair. (cdr) (cdr y)))))) > (pair. '(x y z) '(a b c))

((x a) (y b) (z c))

6. (assoc.  x y) toma un atom x y una lista y de la forma creada por pair., y

devuelve el segundo elemento de la primera lista en  y cuyo primer elemento es x.

(defun assoc. (x y)

(cond ((eq (caar y) x) (cadar y)) ('t (assoc. x (cdr y))))) > (assoc. 'x '((x a) (y b))) a > (assoc. 'x '((x new) (x a) (y b))) new 7

(8)

4 La Sorpresa

Por tanto podemos definir funciones que concatenan listas, substituyen una expresión por otra, etc. Una notación elegante, tal vez, pero ¿y qué? Ahora viene la sorpresa. Resulta que también  podemos escribir una función que funciona como interprete para nuestro lenguaje: una función

que toma como argumento cualquier expresión Lisp, y devuelve su valor. Aquí esta:

(defun eval. (e a) (cond

((atom e) (assoc. e a)) ((atom (car e))

(cond

((eq (car e) 'quote) (cadr e))

((eq (car e) 'atom) (atom (eval. (cadr e) a)))

((eq (car e) 'eq) (eq (eval. (cadr e) a)

(eval. (caddr e) a)))

((eq (car e) 'car) (car (eval. (cadr e) a)))

((eq (car e) 'cdr) (cdr (eval. (cadr e) a)))

((eq (car e) 'cons) (cons (eval. (cadr e) a) (eval. (caddr e) a))) ((eq (car e) 'cond) (evcon. (cdr e) a))

('t (eval. (cons (assoc. (car e) a) (cdr e))

a)))) ((eq (caar e) 'label)

(eval. (cons (caddar e) (cdr e))

(cons (list (cadar e) (car e)) a))) ((eq (caar e) 'lambda)

(eval. (caddar e)

(append. (pair. (cadar e) (evlis. (cdr e) a)) a)))))

(defun evcon. (c a)

(cond ((eval. (caar c) a) (eval. (cadar c) a))

('t (evcon. (cdr c) a)))) (defun evlis. (m a)

(cond ((null. m) '())

('t (cons (eval. (car m) a)

(evlis. (cdr m) a)))))

La definición de eval. es más larga que cualquiera de las otras que hemos visto antes.

Analicemos como funciona cada parte.

La función toma dos argumentos: e, la expresión a ser evaluada, y a, una lista que representa

los valores que se le han dado a los atoms al aparecer como parámetros en las llamadas a función.

(9)

A esta lista se le llama el entorno y es del tipo creada por pair.. Fue con la intención de

construir y buscar estas listas que escribimos pair. y assoc..

La espina dorsal de eval. es una expresión cond con cuatro cláusulas. Cómo evaluamos

una expresión depende de que tipo sea. La primera cláusula maneja atoms. Si e es un atom,

 buscamos su valor en el entorno:

> (eval. 'x '((x a) (y b))) a

La segunda cláusula de eval. es otra cond para manejar expresiones de la forma (a …),

donde a es un atom. Esta incluye todos los usos de los operadores primarios, y hay una

cláusula para cada uno.

> (eval. '(eq 'a a) '()) t

> (eval. '(cons x '(b c)) '((x a) (y b))) (a b c)

Todos estos (excepto quote) llaman a eval. para encontrar el valor de los argumentos.

Las últimas dos cláusulas son más complicadas. Para evaluar una expresión cond llamamos a

una función auxiliar denominada evcon., que se abre camino a través de las cláusulas

recursivamente, buscando una en la que el primer elemento devuelva t. Cuando encuentra tal

cláusula devuelve el valor del segundo elemento.

> (eval. '(cond ((atom x) 'atom) ('t 'list))

'((x '(a b)))) list

La última parte de la segunda cláusula de eval. maneja llamadas a función que han sido

 pasadas como parámetros. Funciona reemplazando al atom con su valor (que debe ser una expresiónlambda o label) y evaluando la expresión resultante. Entonces

(eval. '(f '(b c))

'((f (lambda (x) (cons 'a x)))))

se convierte a

(eval. '((lambda (x) (cons 'a x)) '(b c)) '((f (lambda (x) (cons 'a x)))))

que devuelve (a b c).

Las últimas dos cláusulas en eval. manejan llamadas a función en las que el primer elemento

(10)

una lista del nombre de la función y la función en si misma al entorno, y llamando luego a

eval. en una expresión con la expresión interior lambda sustituida por la expresión label. Es decir,

(eval. '((label firstatom (lambda (x)

(cond ((atom x) x) ('t (firstatom (car x)))))) y) '((y ((a b) (c d))))) se convierte en (eval. '((lambda (x) (cond ((atom x) x) ('t (firstatom (car x))))) y) '((firstatom

(label firstatom (lambda (x)

(cond ((atom x) x)

('t (firstatom (car x))))))) (y ((a b) (c d)))))

que eventualmente devuelve a.

Finalmente, una expresión de la forma ((lambda ( p1... pn) e) a1...an) es evaluada

llamando en primer lugar evlis. para obtener una lista de valores(v1 ... vn) de los

argumentos a1...an, y evaluando luego e con( p1 v1) ... ( pn vn) añadido al frente del

entorno. Entonces

(eval. '((lambda (x y) (cons x (cdr y))) 'a

'(b c d)) '())

se convierte en

(eval. '(cons x (cdr y))

'((x a) (y (b c d))))

que eventualmente devuelve (a c d).

5 Repercusiones

Ahora que entendemos como funciona eval, demos un paso atrás y consideremos lo que

significa. Lo que tenemos aquí es un extraordinariamente elegante modelo de computación. Utilizando sóloquote, atom, eq, car, cdr, cons, y cond, podemos definir una función,

eval., que en realidad implementa nuestro lenguaje, y luego utilizando eso podemos definir cualquier 

(11)

Ya había modelos de computación, por supuesto ― el más notable la Maquina de Turing. Pero

leer los programas de la Maquina de Turing no es muy edificante. Si quieres un lenguaje para describir algoritmos, puede que desees algo más abstracto, y esa fue una de las metas de

McCarthy al definir Lisp.

El lenguaje que definió en 1960 carecía de mucho. No tiene efectos secundarios, no tiene ejecución secuencial (que de cualquier manera sólo es útil con efectos secundarios), no tiene números prácticos4 ni ámbito dinámico. Pero sorprendentemente estas limitaciones pueden ser  remediadas con muy poco código adicional. Steele y Sussman muestran como hacerlo en un famoso articulo llamado The Art of the Interpreter.5

Si comprendes el eval de McCarthy, comprendes más que sólo una etapa en la historia de los

lenguajes. Estas ideas son todavia el núcleo semántico de Lisp hoy en día. Así que estudiar el articulo original de McCarthy nos muestra, en cierto sentido, lo que Lisp es realmente. No es tanto algo que McCarthy diseñara como algo que descubrió. No es intrínsecamente un lenguaje  para IA o prototipado rápido, o cualquier otra tarea de ese nivel. Es lo que obtienes (o una cosa

que obtienes) cuando tratas de axiomatizar la computación.

Con el tiempo, el lenguaje promedio, queriendo decir con esto el lenguaje utilizado por el  programador promedio, ha crecido consistentemente hasta acercarse a Lisp. Así que al

comprender eval estas comprendiendo lo que probablemente será el principal modelo de

computación en el futuro.

 4

Es posible hacer aritmética en el Lisp de 1960 de McCarthy utilizando por ejemplo una lista de natoms para representar el numeron.

(12)

Notas

Al traducir las notaciones de McCarthy a código funcional he tratado de cambiar lo menos  posible. Estuve tentado a hacer el código más fácil de leer, pero quise conservar el sabor del

original.

En el articulo de McCarthy falso es representado por f, no por la lista vacía. Utilice () para

representar falso para que los ejemplos funcionaran en Common Lisp. En ningún lugar el código depende en que ocurra falso para que también sea la lista vacía; nada esta nunca en contra sobre el resultado devuelto por un predicado.

Me salté el construir listas a partir de pares de puntos, porque no los necesitas para comprender 

eval. También me salté mencionar apply, aunque fue apply (una forma muy temprana

de ella, cuyo propósito principal era aplicar comillas a los argumentos) lo que McCarthy llamo en 1960 la función universal; eval era entonces solo una subrutina que apply llamaba para

realizar todo el trabajo.

Definí a list y los c xrs como abreviaciones porque así es como McCarthy lo hizo. De

hecho los c xrs podían haber sido todos definidos como funciones ordinarias. Igual list si

modificábamos eval, lo que podríamos hacer fácilmente, para permitir que las funciones

tomaran cualquier cantidad de argumentos.

El articulo de McCarthy sólo tenia cinco operadores primarios. Utilizó cond y quote pero

 pudo haber pensado en ellos como parte de su metalenguaje. De igual forma no definió los operadores lógicos and y not, pero esto no es tanto problema porque las versiones adecuadas

 pueden ser definidas como funciones.

Al definir eval. llamamos otras funciones como pair. y assoc., pero cualquier llamada

a alguna de las funciones que definimos en función de los operadores primarios puede ser  reemplazada por una llamada a eval.. Es decir,

(assoc. (car e) a)

 pudo haber sido escrita como

(eval. '((label assoc.

(lambda (x y)

(cond ((eq (caar y) x) (cadar y)) ('t (assoc. x (cdr y)))))) (car e)

a)

(cons (list 'e e) (cons (list 'a a) a)))

Había un pequeño error en el eval. de McCarthy. La línea 16 era (equivalente a)

(evlis. (cdr e) a) en lugar de sólo (cdr e), lo que provocaba que los argumentos

(13)

descripción de eval. todavía no había sido implementada en el lenguaje de maquina IBM

704 cuando el articulo fue enviado. También demuestra lo difícil que es estar seguro de la longitud correcta de cualquier programa sin ejecutarlo primero.

Encontré otro problema en el código de McCarthy. Después de dar la definición de eval pasa

a dar algunos ejemplos de funciones de orden superior ―funciones que toman otras funciones

como argumentos. Él define maplist:

(label maplist

(lambda (x f)

(cond ((null x) '())

('t (cons (f x) (maplist (cdr x) f))))))

luego lo utiliza para escribir una sencilla función diff para diferenciación simbólica. Pero diff

 pasa a maplist una función que utiliza x como un parámetro, y la referencia a este es capturada por 

el parámetrox dentro de maplist.6

Es un elocuente testimonio a los peligros del ámbito dinámico que incluso ya el primer ejemplo de funciones Lisp de orden superior estaba roto debido a ello. Puede ser que McCarthy no estuviera completamente consciente de las implicaciones del ámbito dinámico en 1960. El ámbito dinámico  permaneció en implementaciones Lisp por un periodo sorprendentemente largo―hasta que Sussman y

Steele desarrollaron Scheme en 1975. El ámbito léxico no complica mucho la definición deeval, pero

 puede hacer más difícil escribir compiladores.



6Los programadores Lisp de hoy día usarían mapcar aquí en lugar de maplist. Este ejemplo clarifica un misterio: porque

maplist esta en Lisp para empezar. Era la función de mapeo original, y mapcar una adición posterior.

Traducido de The Roots of Lisp por Paul Graham. Traducción: Armando Alvarez con la colaboración de Alonso Soto y Hanedi Salas

Referencias

Documento similar

Este documento destaca nuestra visión colectiva sobre la Transición Energética Justa, tal como debatieron las/os participantes y se expresó en los seminarios virtuales de Amigos de

Por ello es que, realmente, no se puede hablar de una actitud radical y beligerante de parte del colectivo que se manifiesta a favor del reconocimiento legal del

En tales circunstancias, una forma de proceder posible sería iniciar una fase preconstitucional de diálogo nacional, como sucedió en Sudáfrica, para reunir a

1. LAS GARANTÍAS CONSTITUCIONALES.—2. C) La reforma constitucional de 1994. D) Las tres etapas del amparo argentino. F) Las vías previas al amparo. H) La acción es judicial en

A fin de investigar eficazmente las transacciones financieras delictivas, los servicios represivos y las autoridades judiciales recibirán equipamiento y formación para

La oferta existente en el Departamento de Santa Ana es variada, en esta zona pueden encontrarse diferentes hoteles, que pueden cubrir las necesidades básicas de un viajero que

Su adopción, prevista en 2013, ofrecerá a los Estados miembros y a las agencias de la UE un marco común para un intercambio de información casi en tiempo real y una cooperación

Los regímenes de certificación de la UE abarcan tanto el cumplimiento de las normas mínimas de producción obligatorias como los requisitos suplementarios relacionados con la