Programación Avanzada (PAV) Examen Parcial —3 de Diciembre de 2002— Ejercicio 1 (Tema 2) Obtener la forma plana (y, en su caso, reordenada) del hecho : 0.5 puntos p(f(a),X,g(Y,X)). Respuesta: A1 = f(X4), X4 = a, A2 = X5, A3 = g(X6,X5) y de la query : ?- p(Z,f(Z),g(a,b)). Respuesta: A1 = X4, A2 = f(X4), X5 = a, X6 = b, A3 = g(X5,X6) Nota: se deben usar los registros de argumento A1,...,An. Recordad que las ecuaciones “eliminables” no deben aparecer. Ejercicio 2 (Tema 2) 1 punto Obtener la secuencia de instrucciones asociada a la siguiente forma plana del hecho p(f(g(X)),Y,g(X)).: A1 = f(X4), X4 = g(X5), A2 = X6, A3 = g(X5) Respuesta: 100: p/3: 101: 102: 103: get_structure f/1, A1 unify_variable X4 get_structure g/1, X4 unify_variable X5 104: 105: 106: 107: get_variable X6, A2 get_structure g/1, A3 unify_value X5 proceed Ejercicio 3 (Tema 3) Completar la siguiente secuencia de instrucciones resultante de compilar el programa Prolog: 1.5 puntos q(a). r(s(b)). p(X,Y) :- q(X), r(Y). ?- p(Z,s(Z)). Respuesta: 100: q/1: 101: 102: r/1: 103: 104: 105: 106: p/2: 107: 108: 109: get_structure a/0, A1 proceed get_structure s/1, A1 unify_variable X2 get_structure b/0, X2 proceed allocate 1 get_variable X3, A1 get_variable Y1, A2 put_value X3, A1 110: call q/1 111: put_value Y1, A1 112: call r/1 113: deallocate 114: query: allocate 0 115: put_variable X3, A1 116: put_structure s/1, A2 117: set_value X3 118: call p/2 119: deallocate 1 Ejercicio 4 (Tema 3) Dado el programa Prolog: 3 puntos clave(a,b). key(s(c)). test(c(A,B,C)) :- clave(A,B), key(C). ?- test(X). cuya secuencia de instrucciones asociada es: 100: clave/2: get_structure a/0,A1 101: get_structure b/0,A2 102: proceed 103: key/1: get_structure s/1,A1 104: unify_variable X2 105: get_structure c/0,X2 106: proceed 107: test/1: allocate 1 108: get_structure c/3, A1 109: unify_variable X3 110: unify_variable X4 111: unify_variable Y1 112: put_value X3,A1 113: put_value X4,A2 114: call clave/2 115: put_value Y1,A1 116: call key/1 117: deallocate 118: query: allocate 0 119: put_variable X2,A1 120: call test/1 <--------- P 121: deallocate 122: halt <------------------------ CP realizad la ejecución de las instrucciones, comenzando en la instrucción apuntada por P y partiendo del siguiente estado para HEAP, STACK y los registros (si los valores que hay escritos cambian, tachad el valor actual y escribid el nuevo a la derecha): X → 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 HEAP REF 1000 STR 1002 c/3 REF 1003 REF 1004 REF 1005 STR 1007 a/0 STR 1009 b/0 STR 1011 s/1 REF 1012 STR 1014 c/0 STR STR STR STR 1002 1007 1009 1011 E → 2000 2001 2002 2003 2004 2005 2006 STACK 1997 122 0 2000 121 1 REF 1005 Registros Xi (Ai) STR 1014 1 2 3 4 REF REF REF REF 1000 1000 1003 1004 REF REF 1003 1004 REF REF 1005 1012 Señalad también la posición en memoria de la variable X y dad su valor al finalizar la ejecución: X = c(a,b,s(c)) Nota: usad la versión “refinada” de bind 2 Ejercicio 5 (Tema 4) Obtener la secuencia de instrucciones resultante de compilar el programa Prolog: 2 puntos reverse(L,R) :- rev(L,nil,R). rev(nil,Acc,Acc). rev(list(H,T),Acc,R) :- rev(T,list(H,Acc),R). ?- reverse(L,R), reverse(R,NL). Respuesta: 100: reverse/2: allocate 0 101: get_variable X4,A1 102: get_variable X5,A2 103: put_value X4,A1 104: put_structure nil/0,A2 105: put_value X5,A3 106: call rev/3 107: deallocate 108: rev/3: try_me_else L1 109: get_structure nil/0,A1 110: get_variable X4,A2 111: get_value X4,A3 112: proceed 113: L1: trust_me 114: allocate 0 115: get_structure list/2,A1 116: unify_variable X4 117: unify_variable X5 3 118: get_variable X6,A2 119: get_variable X7,A3 120: put_value X5,A1 121: put_structure list/2,A2 122: set_value X4 123: set_value X6 124: put_value X7,A3 125: call rev/3 126: deallocate 127: query: allocate 1 128: put_variable X3,A1 129: put_variable Y1,A2 130: call reverse/2 131: put_value Y1,A1 132: put_variable X4,A2 133: call reverse/2 134: deallocate Ejercicio 6 (Tema 4) 1 punto En la compilación de las reglas empleamos la instrucción allocate cuyo objetivo es almacenar en el STACK los entornos de activación de procedimiento. Dichos entornos almacenan tanto las variables permanentes del procedimiento como el valor actual del registro CP. Considera, por ejemplo, el siguiente programa Prolog: p(X,Y) :- q(X), r(Y). ---> allocate 1 ?- p(A,B), (*) otras_llamadas. En este caso, la ejecución de la instrucción allocate tendrá como efecto almacenar en el STACK el valor de la variable permanente “Y” ası́ como el valor del registro CP (que apuntará a la posición (*)). Sin embargo, parte de esta información no es siempre necesaria. Completa el programa anterior con las definiciones para los procedimientos “q” y “r” de forma que la instrucción allocate pueda eliminarse sin que se pierdan ni los valores de las variables permanentes ni el valor correcto del registro CP. Si piensas que esto no es posible, explica porqué. Respuesta: No es posible. El motivo es que, independientemente de la definición de los procedimientos “q” y “r”, el valor del registro CP siempre se perderá al ejecutar la instrucción call q/1. Ejercicio 7 (Tema 4) 1 punto Los programas recursivos pueden consumir una gran cantidad de memoria en tiempo de ejecución. Sin embargo, en ciertos casos es posible mejorar esta situación mediante la optimización conocida como LCO (“Last Call Optimization”). Dicha optimización consiste, esencialmente, en liberar la memoria del STACK justo antes de realizar la última llamada del procedimiento. Por ejemplo, dado el siguiente código: p/1: allocate 0 get_variable X2,A1 put_value X2,A1 call p/1 deallocate asociado a la cláusula “p(X) : −p(X)”, la optimización LCO generarı́a el siguiente código: p/1: allocate 0 get_variable X2,A1 put_value X2,A1 deallocate call p/1 (*) (**) Es decir, primero se elimina el entorno del STACK (*) y luego se realiza la última llamada del procedimiento (**). Sin embargo, para que este cambio sea correcto, es necesario modificar ligeramente la definición de la instrucción call. Indica cual deberı́a ser la nueva definición de la instrucción call para que funcione correctamente el ejemplo anterior. Respuesta: deallocate ≡ CP ← STACK[E + 1]; E ← STACK[E]; P ← P + instruction size(P); call p/n ≡ num of args ← n; P ← @(p/n); 4