CONSTRUCTIVISMO Y LISP EN EL LIBRO PERICIA ARTIFICIAL: UN APRENDIZAJE CONSTRUCTIVISTA DE SISTEMAS EXPERTOS Alejandro Guerra Hernández El término constructivista en el título de libro Pericia Artificial: un aprendizaje constructivista de sistemas expertos (1996), se refiere a una idea que José Negrete ya planteaba un lustro an­ tes de la aparición de este texto: “…Si la Inteligencia Artificial (IA) se debe desarrollar en México, nuestra actitud pedagógica debe ser diferente a la descrita (glosar alrededor de un tema con un tratamiento enciclopédico): debemos habilitarnos en la expe­ rimentación de la IA, de tal manera que los conceptos básicos de esta disciplina no nos queden difusos”.3 Hacer IA para entender­ la. Tal cambio pedagógico, que descansa en las ideas de Piaget en alas de Seymour Papert, tiene como instrumento idóneo la programación funcional, originalmente Logo, y Lisp en el caso de nuestra pericia artificial. Como autor material de buena parte del asunto que hoy nos ocupa, este capítulo se centrará en la importancia de Lisp respecto a la estrategia constructivista adoptada en Pericia Artificial… La idea de esta presentación se le debe a un re­ visor, de afortunada anonimia, que argumentó que el aspecto positivo para resaltar en un artículo nuestro sobre una nueva 3 José Negrete Martínez, Inteligencia artificial en computadoras, 2a ed., Limusa, México, 1991. 157 InteligenciaArtificialNegrete.indd 157 20/03/2013 12:01:09 p.m. teoría del aprendizaje incremental en agentes intencionales era que: ¡habíamos decidido abandonar Lisp en favor de Java! Pero si Java deteriora intelectualmente –me dije parafrasean­ do a Negrete, quien a su vez parafrasea a Dijkstra–.4 Antes de entrar en materia, es menester señalar que las ideas pedagógicas mencionadas anteriormente maduraron en Pericia Artificial… influidas por las propuestas de la robótica reactiva, configurando así un libro de texto sobre los sistemas basados en el conocimiento que descansa en una metodología propia de los sistemas cimentados en la conducta. Los resulta­ dos esperados pueden resumirse en los siguientes puntos: !"#$"%&$'$()$"$(*$+,&"#-*'$.,*"/0%$&'1*"2SE) a partir de la construcción de módulos programáticos autónomos como funciones que hacen uso de la memoria y los datos del SE. !"3,",4&$4,5-6(")$".6)781*"%&1)75$"SE de mayor compleji­ dad, en un proceso incremental. !" #-" 9-$(" 8," ,%&10-.,5-6(" %7&,.$('$" -(5&$.$(',8" $*" )$­ seable, en ocasiones será necesario introducir reajustes a los módulos previamente definidos. !" 31*" ,:,(5$*" )$8" 8$5'1&" %7$)$(" *$&" :,8-),)1*" %1&" ;*'$" ," través de ejemplos, experimentos resueltos y experi­ mentos propuestos a lo largo del libro (cuya tipografía fue causa de desvelos y una serie de desavenencias con nuestra casa editorial). De forma que el present capítulo abordará dos cuestiones: ¿de qué manera Lisp contribuye al logro de las metas pedagógicas ex­ puestas anteriormente?; y, de manera muy breve, su relevancia en el estudio de la IA y los Sistemas basados en el Conocimiento. 4 Basic deteriora intelectualmente, ibídem, p. 15 158 InteligenciaArtificialNegrete.indd 158 20/03/2013 12:01:10 p.m. Lisp y la pedagogía del Pericia Artificial… En esta sección resaltan las contribuciones de Lisp en la estra­ tegia pedagógica: la incrementalidad, interactividad incluida; la agregación y la complejidad; y un punto no incluido en el listado anterior: la desmitificación del dictum de Ada Lovelace (una computadora solo puede hacer aquello para lo cual fue programada). Incrementalidad e interacción: ¿es el REPL idiota? El ambiente de programación de Lisp (pero también el de Logo, Caml, Scheme y demás lenguajes funcionales; así como el de Prolog, Mercury y demás sistemas de programación lógica) es el toplevel interactivo o REPL (Read­Eval­Print­Loop). El toplevel se materializa en una consola donde el usuario puede capturar expresiones del lenguaje de programación que son validadas al momento de ser leídas y aprobadas por un analizador sintáctico o parser (Read); igualmente, son evaluadas de adentro hacia afuera, computando primero los argumentos y luego las funcio­ nes (Eval), y el resultado final es comunicado al usuario (Print) para quedar en espera de una nueva expresión. Debido a esta dinámica, el REPL se confunde muchas veces con un intérprete. Ninguna de las implementaciones actuales de Lisp son interpretadas; todas se basan en eficientes com­ piladores, pero su ambiente de programación sigue siendo el REPL . La confusión también ocurre en el sentido contrario, no todo intérprete tiene como ambiente de programación al REPL. La importancia del REPL radica en que hace posible e indu­ ce una aproximación incremental e interactiva a la solución de problemas bien conocida por los programadores Lisp. Tómese como ejemplo la tarea de programar la desviación estándar a partir de su formulación: 159 InteligenciaArtificialNegrete.indd 159 20/03/2013 12:01:10 p.m. Un programador Lisp comenzaría por implementar las funcio­ nes necesarias para computar las sub­expresiones de <, por ejemplo, cuadrado y longitud de una lista para poder calcu­ laryN. Es muy común interaccionar con el REPL para verificar la solución de un caso particular del problema que queremos resol­ ver, para proceder substituyendo las constantes de ese caso por variables, y obtener así la solución general buscada: > (* 5 5) 25 > (defun cuadrado (x) (* x x)) CUADRADO > (cuadrado 5) 25 Se puede proceder de igual manera utilizando funciones primi­ tivas del lenguaje. Si necesito computar la longitud de una lista, pruebo si la función predefinida length se ajusta a mis necesidades: > (length ‘(1 2 3)) 3 > (length ‘()) 0 nos indica que podemos sustituir la lista ’(1 2 3) por cualquier otra en la solución de nuestro problema; y que la función está bien definida para el caso de la lista vacía. Esta verificación inte­ ractiva avala la aplicación de las funciones definidas en aquéllas por definir; por ejemplo, puedo comenzar por definir media como sigue y validar su comportamiento: 160 InteligenciaArtificialNegrete.indd 160 20/03/2013 12:01:10 p.m. > (defun media (lista) (/ (apply #’+ lista) (length lista))) MEDIA > (media ‘(2 22)) 2 > (media ‘(2 4 2)) 8/3 > (media ‘() ERROR: Divisionby Zero Puesto que media no funciona correctamente en el caso de la lista vacía, procedemos a su redefinición: > (defun media (lista) (let ((l (length lista))) (if (equal l 0) 0 (/ apply #’+ lista (length lista))))) MEDIA > (media ‘(2 22)) 2 > (media ‘(2 4 2)) 8/3 > (media ‘() 0 obteniendo así el comportamiento deseado. Siguiendo los pre­ ceptos de la programación funcional, una función pura como media puede usarse de manera segura en otras funciones des­ pués de haber sido verificada: 161 InteligenciaArtificialNegrete.indd 161 20/03/2013 12:01:10 p.m. > (defundesv­std (lista) (sqrt (­ (/ (apply #’+ (mapcar #’cuadrado lista)) (length lista)) (cuadrado (media lista))))) DESV­STD De esta manera, Lisp provee un ambiente de programación donde la solución incremental a un problema, incluida la vali­ dación de las soluciones parciales, no solo es posible, si no que es inherente a la metodología de programación. Agregación: funciones de primera clase Es obvio que el REPL facilita la obtención de soluciones por agregación. No es necesario definir todas las funciones involu­ cradas en el cómputo de la desviación estándar para poder eje­ cutar tal función. En realidad, obtuvimos desv­std al agregar cuadrado y luego media a nuestro sistema. Esta es la forma más obvia de agregación en Lisp. En la definición de dev­std, apply y mapcar reciben una función como parte de sus argumentos. Esto es posible porque las funciones en Lisp son ciudadanos de primera clase. No hay nada que las diferencie de otro dato, y pueden pasarse como argumento a otras funciones, lo cual introduce una nueva for­ ma de agregación: la aplicación funcional: > (mapcar #’cuadrado ‘(1 2 3)) (1 4 9) > (mapcar #’cuadrado (mapcar #’cuadrado ‘(1 2 3))) (1 16 81) 162 InteligenciaArtificialNegrete.indd 162 20/03/2013 12:01:11 p.m. El dictum de Ada Lovelace: macros y representación uniforme Hay un argumento a favor de Lisp que no está presente en otros lenguajes que usan el REPL: la representación uniforme de programa y datos. Observemos que la sintaxis de Lisp se reduce a la siguiente formulación <<<<Lisp si y solo si ato­ mo(<) o lista(<). Si consideramos los ejemplos anteriores, (1 2 3) es una lista que utilizamos como argumento (dato) para probar length. Pero la definición de cuadrado (defun cuadrado (x) (* x x)) es también una lista. Esta unicidad en la representación de Lisp nos permite escri­ bir fácilmente programas que generan programas, con la finali­ dad no solo de complicarle el legado a Ada Lovelace (las compu­ tadoras no podrán hacer nada que no haya sido programado en ellas), sino para obtener programas más flexibles y autónomos extendiendo nuestro lenguaje de programación original. Consideremos el siguiente ejemplo: Quisiera programar una función que aleatoriamente elija el argumento a evaluar; por ejemplo, si tengo un robot atorado en una esquina, me gustaría que a veces el robot saliera por la izquierda y otras veces por la derecha, ejecutando (eleccion­aleatoria (a­la­izq) (a­la­der)). Si abordamos esta definición como una función tenemos un problema: no queremos que todos sus argumentos sean evaluados. Es decir, esta función debería ser una abreviatura de: (case (random 2) (0 (a­la­izq)) (1 (a­la­der))) La forma de implementar eleccion­aleatoria es como una macro: 163 InteligenciaArtificialNegrete.indd 163 20/03/2013 12:01:11 p.m. (defmacroeleccion­aleatoria (&restexprs) `(case (random ,(length exprs)) ,@(let ((key ­1)) (mapcar #’(lambda (expr) `(,(incfkey), expr)) exprs)))) Esta definición extiende mi lenguaje con una nueva estructura de control eleccion­aleatoria que es más flexible que case; pue­ de operar sobre cualquier lista de elecciones: > (eleccion­aleatoria ‘pri ‘pan ‘prd ‘) > (eleccion­aleatoria ‘aguila ‘sol) Para terminar esta sección con un buen sabor de boca, observen que las macros generalizan funciones, y las funciones generali­ zan soluciones particulares. De forma que las macros constitu­ yen un escalón más en la incrementalidad que Lisp ofrece. Lisp e Inteligencia Artificial En esta sección argumentaré que Lisp es una herramienta para hacer IA y, al mismo tiempo, sujeto de estudio de la IA. Históri­ camente esto es evidente. La propuesta de investigación de John McCarthy para la fundacional conferencia de Dartmouth señala: “por lo tanto resulta deseable intentar construir un lenguaje arti­ ficial tal que una computadora pueda ser programada para usar­ lo en problemas que requieren conjetura y auto­referencia […] Es­ pero tratar de formular un lenguaje con estas propiedades y que contenga además las nociones de objeto físico, evento, etcétera”. Entre los invitados a la conferencia de Dartmouth estaban Allen Newell y Herbert Simon, que desembarcaron con un pro­ 164 InteligenciaArtificialNegrete.indd 164 20/03/2013 12:01:11 p.m. grama ejecutable que probaba y manipulaba teoremas lógicos en una computadora de la RAND­Corporation. Ellos llamaban a su sistema “máquina lógico teórica”, exagerando sobre el hardware como era común en la época. Hubiera sido más apro­ piado hablar de un nuevo lenguaje de programación ( LL) que introducía un concepto invaluable: facilidades para el procesa­ miento de listas. Como sea, McCarthy no se entusiasmó tanto por el lenguaje LL , como por algunas de las ideas de Fortran. Estaba fascinado con la ilusión de escribir programas con una semántica algebraica. En los siguientes dos años, McCarthy desarrolló la idea de extender un lenguaje según Fortran, con soporte para el ma­ nejo de listas, teniendo en cuenta, desde 1956, que había que trabajar con expresiones simbólicas para alcanzar las metas de la IA planteadas en Dartmouth. Y, en el año de 1957, convenció a Rochester de que este era el tipo de lenguaje útil para imple­ mentar un demostrador de teoremas propuesto por Minsky. Allen Newell hizo una interesante observación al abordar la peculiar metodología de la IA. La hipótesis del sistema de símbolos físicos identifica una clase de sistemas que encarnan la naturaleza esencial del símbolo y su condición necesaria y suficiente para generar agentes inte­ ligentes. Tales sistemas resultaron ser sistemas de cómputo universales, vistos desde un ángulo diferente. Lo relevante aquí es que tal hipótesis emergió de la práctica de la IA a partir del desarrollo de lenguajes de procesamiento de listas, en especial Lisp; y de la estructura que estos programas adoptaron uno tras otro. Adquirimos la noción adecuada de símbolo en la IA , por nuestra práctica de la IA. He aquí un segundo argumento a favor de la adopción de Lisp en un libro como Pericia Artificial… y a favor de la estrategia 165 InteligenciaArtificialNegrete.indd 165 20/03/2013 12:01:11 p.m. de hacer IA para entenderla. Lisp no es solo una herramienta adecuada para la práctica de la IA, sino que es sujeto de estu­ dio de la misma. Los SE son resultado de las nociones de sím­ bolo y búsqueda adoptada por Newell y Simon, verificadas e influidas, a su vez, por las S­Expresiones de Lisp y la agrega­ ción de funciones a éste hasta llegar a Shells y demás ambien­ tes de programación más adecuados como herramientas. Mi reflexión puede extenderse naturalmente a Prolog. Esta particularidad metodológica de la IA no debe pasarse por alto: la programación funcional y la programación lógica son sujeto de estudio y herramientas para su desarrollo. Su adecuación ingenieril a los problemas propios de la IA no es, por tanto, fortuita. Y, por supuesto, su relevancia para la IA va más allá de la ingeniería. Quedan algunas preguntas en el aire, disfrazadas de pregunta única, para terminar esta pre­ sentación: ¿Es Java sujeto de estudio de la IA? Bibliografía NEGRETE MARTÍNEZ, José, P. P. González y Alejandro Guerra (1996). Pericia Artificial: un aprendizaje constructivista de sistemas expertos. Universidad Veracruzana, México. 166 InteligenciaArtificialNegrete.indd 166 20/03/2013 12:01:11 p.m.