slide1 n.
Download
Skip this Video
Loading SlideShow in 5 Seconds..
VII. Programación y Depuración en Prolog PowerPoint Presentation
Download Presentation
VII. Programación y Depuración en Prolog

Loading in 2 Seconds...

play fullscreen
1 / 58
latika

VII. Programación y Depuración en Prolog - PowerPoint PPT Presentation

201 Views
Download Presentation
VII. Programación y Depuración en Prolog
An Image/Link below is provided (as is) to download presentation

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.

- - - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript

  1. VII. Programación y Depuración en Prolog Jorge Cabrera Gámez Departamento de Informática y Sistemas Universidad de Las Palmas de Gran Canaria Prolog VII

  2. Índice. • Normas básicas de estilo • Depuración de Programas • Evaluación del rendimiento del sistema • Sumario Prolog VII

  3. Un buen programa es ... • Correcto • Eficaz • Transparente, inteligible • Adaptable • Robusto • Documentado Prolog VII

  4. Normas básicas de estilo 1. Pensar en Prolog: Descomponer el problema Enumerar los casos posibles Refinar progresivamente Recursividad Prolog VII

  5. Ejemplo: Definir procedimiento que nos permita aplicar una determinada regla (F) de transformación sobre todos los elementos de una lista (Lista) para producir una nueva lista (NuevaLista). map(Lista, F, NuevaLista) Prolog VII

  6. Casos posibles: map(Lista, F, NuevaLista) • 1. Lista = [ ] • NuevaLista = [ ] • 2. Lista = [ X | Cola ] • Transformar el item X en NX por la regla F, • Transformar Cola en Ncola. • La lista transformada completa es [ NX | NCola ] map([ ],_, [ ]). map([X|Cola], F, [NX | NCola]) :- G =.. [F, X, NX], call(G), map(Cola, F, NCola). Prolog VII

  7. Normas básicas de estilo 1. Pensar en Prolog: Descomponer el problema Enumerar los casos posibles Refinar progresivamente Recursividad 2. La organización del código Adoptar un estilo estándar Identar Comentar Dividir en módulos Prolog VII

  8. Algunas Reglas del “Buen Programar” • Las cláusulas deberían ser cortas • Nombrar las variables de forma “sugerente” • El formato del código debe facilitar su comprensión • El estilo debe ser constante • Documentar, al menos lo básico • Recursos a emplear con cuidado: • cut • not • retract, assert Prolog VII

  9. ordena(Lista1, Lista2, Lista3) Ejemplo: ordena([ 2,4,7], [3,4,8 ], [2,3,4,4,8 ]) ordena(Lista1, Lista2, Lista3) :- Lista1 = [ ], !, Lista3 = Lista2; Lista2 = [ ], !, Lista3 = Lista1; Lista1 = [ X|Rest1], Lista2 = [ Y|Rest2], (X < Y, !, Z = X, ordena(Rest1, Lista2, Rest3); Z = Y, ordena(Lista1, Rest2, Rest3)), Lista3 = [ Z|Rest3]. Prolog VII

  10. ordena(Lista1, Lista2, Lista3) Ejemplo: ordena([ 2,4,7], [3,4,8 ], [2,3,4,4,8 ]) ordena([ ], Lista, Lista) :- !. ordena(Lista, [ ], Lista). ordena([ X|Rest1], [Y|Rest2], [ X|Rest3]) :- X < Y, !, ordena(Rest1, [Y|Rest2], Rest3). ordena(Lista1, [Y|Rest2], [Y|Rest3]) :- ordena(Lista1, Rest2, Rest3). Prolog VII

  11. Listas “diferencia” Se denominan “listas diferencia” (difference lists) a una forma de representar listas en Prolog que - como técnica de programación - puede provocar un notable incremento de eficiencia. Ejemplo: Supongamos que deseamos diseñar un procedimiento que nos permita añadir un elemento a una lista por la cabeza. add_to_head(X,Ys,[X|Ys]). Esto es fácil. Supongamos ahora que deseamos diseñar el procedimiento complementario add_to_back. Prolog VII

  12. Ejemplo (cont): Realmente no es muy difícil ... add_to_back(X, [ ], [X]). add_to_back(X, [Y|Ys], [Y|Zs]):- add_to_back(X,Ys,Zs). Sin embargo, es terriblemente ineficiente por motivos evidentes. Ejemplo: Algo similar ocurre con la definición estándar de append/3: append([ ], Ys, Ys). append([X|Xs], Ys, [X|Zs]):- append(Xs,Ys,Zs). Prolog VII

  13. Las listas diferencia permiten manipular listas de forma mucho más eficiente definiendo “patrones de listas”. Por ejemplo: difference_append (A-Z, Z-B, A-B). ?- difference_append([a,b,c], [d,e], R). No. ?- difference_append([a,b,c]-Z, Z-[d,e], R). Z = _G379 R = [a, b, c]-[d, e] Yes ?- difference_append([a,b,c|Z] - Z, [d,e] - [ ], R- [ ]). Z = [d, e] R = [a, b, c, d, e] Yes ?- difference_append([a,b,c|Z] - Z, [d,e] - [ ], R). Z = [d, e] R = [a, b, c, d, e] - [ ] Yes Prolog VII

  14. Las siguientes definiciones transforman una lista diferencia en una lista “normal”, pero no a la inversa dl_to_list([ ] - _, [ ]) :- !. dl_to_list([X|Y] - Z, [X|W]) :- dl_to_list(Y - Z, W). ?- dl_to_list([1,2,3|X]-X,L). X = [ ] L = [1,2,3]; No Recíprocamente, list_to_dl transforma una lista “normal” en una lista diferencia, pero no a la inversa list_to_dl([], X - X). list_to_dl([X|W], [X|Y] - Z) :- list_to_dl(W, Y - Z). ?- list_to_dl([a,b,c],Y-Z). Y = [a, b, c|_G167] Z = _G167 ; No Prolog VII

  15. Un truco con la doble negación. Imaginemos las siguientes definiciones: pred(a,a). pred(a,b). pred(c,c). Y un problema un tanto esotérico ... ¿Cómo podríamos definir un predicado que comprobase que el predicado pred(X,X) se verifica pero que no asignara las variables, es decir, que no diese un valor a la variable X? Prolog VII

  16. Podría pensarse en algo como ... ?- pred(X,X) pero esto asigna valores a las variables. O en utilizar variables anónimas ... ?- pred(_,_). pero esto no funcionaría en el caso que queramos comprobar la verificación de pred/2 cuando los dos argumentos son iguales. Prolog VII

  17. La solución puede construirse empleando la doble negación de forma muy sencilla: ?- \+(\+pred(X,X)). X = _G240 Yes ?- \+(\+pred(X,X)), X = f. X = f Yes ?- X = f, \+(\+pred(X,X)). No pred(a,a). pred(a,b). pred(c,c). Prolog VII

  18. ?- \+(\+pred(X,X)), X=a, \+(\+pred(X,X)). X = a Yes ?- \+(\+((X=c,pred(X,X)))). X = _G332 Yes ?- \+(\+((X=c,pred(X,X)))), \+(\+((X=a,pred(X,X)))). X = _G485 Yes pred(a,a). pred(a,b). pred(c,c). Prolog VII

  19. El modelo de cuatro puertos. Objetivo call exit fail redo • Evento Redo: cuando Prolog vuelve a considerar este objetivo e intenta verificarlo de nuevo. • Evento Fail: cuando Prolog no ha conseguido verificar el objetivo. • Evento Call: cuando Prolog intenta verificar el objetivo por primera vez. • Evento Exit: cuando Prolog ha verificado el objetivo. Prolog VII

  20. Predicados predefinidos para depuración debug: Activa el depurador. Tanto spy como trace lo activan. trace: trace(+Pred) trace(+Pred,+Ports): tracea la verificación del predicado Pred. Es posible indicar qué predicado y sobre qué puertos (eventos) se desea seguir la traza. spy(+Pred): Similar a trace(+Pred), pero permite interactuar con el intérprete tras la activación de un evento. Prolog VII

  21. Predicados predefinidos para depuración nodebug: Desactiva el depurador. notrace. notrace(+Pred). nospyall nospy(+Pred): Desactiva la actividad de spy sobre el predicado Pred debugging: Ofrece información sobre el estado del depurador y lista los predicados marcados con trace o spy. leash(?Ports): Activa o desactiva los puertos susceptibles de interacción con spy Prolog VII

  22. Ejemplos: ?- [user]. |: añade([],Y,Y). |: añade([A|B],C,[A|D]):- añade(B,C,D). |: user compiled, 75.41 sec, 396 bytes. Yes ?- añade([a,b],[c],L). L = [a, b, c] Yes ?- trace(añade). añade/3: call redo exit fail Prolog VII

  23. Ejemplos: ?- añade(X,[c],[a,b,c]). T Call: ( 8) añade(_G201, [c], [a, b, c]) T Call: ( 9) añade(_G311, [c], [b, c]) T Call: ( 10) añade(_G314, [c], [c]) T Exit: ( 10) añade([], [c], [c]) T Exit: ( 9) añade([b], [c], [b, c]) T Exit: ( 8) añade([a, b], [c], [a, b, c]) X = [a, b] ; T Redo: ( 10) añade(_G314, [c], [c]) T Call: ( 11) añade(_G317, [c], []) T Fail: ( 11) añade(_G317, [c], []) T Fail: ( 10) añade(_G314, [c], [c]) T Fail: ( 9) añade(_G311, [c], [b, c]) T Fail: ( 8) añade(_G201, [c], [a, b, c]) No ?- añade([a,b],[c],L). T Call: ( 8) añade([a, b], [c], _G188) T Call: ( 9) añade([b], [c], _G290) T Call: ( 10) añade([], [c], _G293) T Exit: ( 10) añade([], [c], [c]) T Exit: ( 9) añade([b], [c], [b, c]) T Exit: ( 8) añade([a, b], [c], [a, b, c]) L = [a, b, c] ; No añade([ ],Y,Y). añade([A|B],C,[A|D]):- añade(B,C,D). Prolog VII

  24. Ejemplos: ?- trace(añade,-all). añade/3: Yes ?- debugging. Debug mode is on; spy points (see spy/1) on: Trace points (see trace/1) on: Yes ?- trace(añade,+call),trace(añade,+exit). añade/3: call añade/3: call exit Yes ?- debugging. Debug mode is on; spy points (see spy/1) on: Trace points (see trace/1) on: añade/3: call exit Yes ?- añade(X,[c],[a,b,c]). T Call: ( 8) añade(_G201, [c], [a, b, c]) T Call: ( 9) añade(_G311, [c], [b, c]) T Call: ( 10) añade(_G314, [c], [c]) T Exit: ( 10) añade([], [c], [c]) T Exit: ( 9) añade([b], [c], [b, c]) T Exit: ( 8) añade([a, b], [c], [a, b, c]) X = [a, b] ; T Call: ( 11) añade(_G317, [c], []) No Prolog VII

  25. ?- añade(X,[c],[a,b,c]). * Call: ( 8) añade(_G201, [c], [a, b, c]) ? creep * Call: ( 9) añade(_G311, [c], [b, c]) ? creep * Call: ( 10) añade(_G314, [c], [c]) ? creep * Exit: ( 10) añade([], [c], [c]) ? creep * Exit: ( 9) añade([b], [c], [b, c]) ? creep * Exit: ( 8) añade([a, b], [c], [a, b, c]) ? creep X = [a, b] ; * Redo: ( 10) añade(_G314, [c], [c]) ? creep * Call: ( 11) añade(_G317, [c], []) ? creep * Fail: ( 11) añade(_G317, [c], []) ? creep * Fail: ( 10) añade(_G314, [c], [c]) ? creep * Fail: ( 9) añade(_G311, [c], [b, c]) ? creep * Fail: ( 8) añade(_G201, [c], [a, b, c]) ? creep No Ejemplos: ?- leash(-call),leash(redo). Yes ?- añade(X,[c],[a,b,c]). * Call: ( 8) añade(_G201, [c], [a, b, c]) * Call: ( 9) añade(_G311, [c], [b, c]) * Call: ( 10) añade(_G314, [c], [c]) * Exit: ( 10) añade([], [c], [c]) ? creep * Exit: ( 9) añade([b], [c], [b, c]) ? creep * Exit: ( 8) añade([a, b], [c], [a, b, c]) ? creep X = [a, b] ; * Redo: ( 10) añade(_G314, [c], [c]) * Call: ( 11) añade(_G317, [c], []) * Fail: ( 11) añade(_G317, [c], []) ? creep * Fail: ( 10) añade(_G314, [c], [c]) ? creep * Fail: ( 9) añade(_G311, [c], [b, c]) ? creep * Fail: ( 8) añade(_G201, [c], [a, b, c]) ? creep No ?- añade(X,[c],[a,b,c]). * Call: ( 8) añade(_G201, [c], [a, b, c]) ? Options: +: spy -: no spy /c|e|r|f|u|a} goal: find .: repeat find a: abort A: alternatives b: break c (return, space): creep d: display e: exit f: fail [depth] g: goals h (?): help i: ignore l: leap L: listing n: no debug p: print r: retry s: skip u: up w: write C: toggle show context * Call: ( 8) añade(_G201, [c], [a, b, c]) ? alternatives [ 8] añade(_G201, [c], [a, b, c]) * Call: ( 8) añade(_G201, [c], [a, b, c]) ? no debug X = [a, b] Yes ?- spy(añade). Spy point on añade/3 Yes ?- debugging. Debug mode is on; spy points (see spy/1) on: añade/3 Trace points (see trace/1) on: Yes Prolog VII

  26. Captura de excepciones en (ISO) Prolog SWI-Prolog define los predicados catch/3 y throw/1 de acuerdo con el estándar de ISO Prolog para el lanzamiento y captura de excepciones. En la actual implementación la mayoría de los predicados predefinidos generan excepciones aunque todavía restan algunos predicados que simplemente emiten un mensaje, lanzan el depurador y fallan (el comportamiento genérico antes de introducir el soporte para el manejo de excepciones). throw(+Excepción) Emite una excepción. El sistema busca la invocación anterior más próxima de catch/3 cuyo 2º argumento (Catcher) se unifica con Excepción. Prolog VII

  27. Captura de excepciones en (ISO) Prolog catch(:Goal, +Catcher, :Recover) Análoga a call/1 si no se produce ninguna excepción mientras se ejecuta Goal. Si se señaliza una excepción mediante throw/1 mientras se ejecuta Goal, y Goal es el objetivo más interno para el que Catcher se unifica con el argumento de throw/1, todos los puntos de exploración alternativos generados por Goal se podan y el sistema se retrotrae (backtracks) al comienzo de catch/3 mientras se preserva el término de excepción producido por thrown/1 y se ejecuta Recover mediante call/1. El sobrecoste de invocar un objetivo mediante catch/3 es aproximadamente el mismo que hacerlo mediante call/1. Sin embargo, es mucho mayor si se produce una excepción, especialmente si el término de excepción es largo debido al coste de la copia. `+' indica que el argumento es de entrada para el predicado `-’ denota a un argumento de salida `?' denota tanto entrada como salida `:' implica que el argumento es módulo-dependiente. Normalmente el argumento es un término invocable que se refiere a un predicado que es específico a un módulo. Prolog VII

  28. Un ejemplo sencillo: print_message(+Tipo, +Term) El predicado print_message/2 se emplea para imprimir mensajes, en especial desde excepciones en un formato inteligible a través de stream user_error. “Tipo” puede tomar los siguientes valores: informational, banner, warning, error, help or silent. Si la bandera de Prolog (ver current_prolog_flag/2) verbose tiene el valor “silent”, los mensajes de tipo “informational” or “banner” son tratados como “silent”. divide(X,Y,D):- catch( divide_aux(X,Y,D), E, (print_message(error, E),fail)). divide_aux(X,Y,D):- D is X/Y. ?- divide_aux(3,2,D). D = 1.5 Yes ?- divide_aux(3,0,D). ERROR: //2: Arithmetic: evaluation error: `zero_divisor' ^ Exception: (7) _G159 is 3/0 ? ^c ?- divide(3,0,D). ERROR: //2: Arithmetic: evaluation error: `zero_divisor' No Prolog VII

  29. Un segundo ejemplo: dot_product(X,Y,R):- catch( same_length(X,Y), different_length, (write_ln('ERROR: dot_product/3: Vectors must have the same dimension'), fail)), catch( dot_product_aux(X,Y,0,R), E, (print_message(error, E),fail)). same_length(X,Y):- length(X,Lx), length(Y,Ly), Lx =:= Ly -> true ; throw(different_length). dot_product_aux([],[],R,R). dot_product_aux([X|Xs],[Y|Ys],A,R):- A1 is A+X*Y, dot_product_aux(Xs,Ys,A1,R). ?- dot_product([2,1],[2,1],R). R = 5 Yes ?- dot_product([2,1],[2],R). ERROR: dot_product/3: Vectors must have the same dimension No ?- dot_product([2,1],[2,a],R). ERROR: Arithmetic: `a/0' is not a function No Prolog VII

  30. Un ejemplo con manejadores de excepciones anidados: top_pred(X,Y,D):- catch(pred1(X,Y,D), error_level_0, write_ln('Error: pred1/3 (catched at level 0)')), write_ln('Este no termina en fallo'). pred1(X,Y,D):- catch(pred2(X,Y,D), error_level_1, (write_ln('Error: pred2/3 (catched at level 1)'), fail)). pred2(X,Y,D):- X > Y -> D is X ; X =:= Y -> throw(error_level_1) ; throw(error_level_0). ?- top_pred(2,1,R). Este no termina en fallo R = 2 Yes ?- top_pred(2,2,R). Error: pred2/3 (catched at level 1) No ?- top_pred(2,3,R). Error: pred1/3 (catched at level 0) Este no termina en fallo R = _G159 Yes ?- top_pred(2,a,R). ERROR: Arithmetic: `a/0' is not a function ^ Exception: (9) catch(pred2(2, a, _G159), error_level_1, (write_ln('Error: pred2/3 (catched at level 1)'), fail)) ? abort % Execution Aborted Prolog VII

  31. Un ejemplo inspirado en la primera práctica del curso Problema: En el ejemplo del restaurante, definir una variante del predicado comida/3, comida_posible/3, de manera que cuando se solicite una comida definiendo de antemano uno o varios de los tres platos verifique que esos platos están en el menú. En particular, comida_posible/3 debería fallar si se invoca seleccionando un plato que no está en el menú. INDICACIÓN: Emplear throw/1 y catch/3. Prolog VII

  32. % % Asegurar que los platos son conocidos % si se invoca comida con algún argumento % instanciado % known_or_var(T,P):- F =.. [T,P], ( nonvar(P), \+F, sformat(E,'El plato \"~w\" no está en la carta.~n', [P]), throw(E) ; F ). platos_del_menu(Entrada, Principal, Postre):- known_or_var(entrada, Entrada), known_or_var(plato_principal, Principal), known_or_var(postre, Postre). comida_posible(Entrada, Principal, Postre):- catch(platos_del_menu(Entrada, Principal, Postre), E, ( format('ERROR: ~w~n.',E), fail)). 2 ?- comida_posible(ensalada,Pp,Po). ERROR: El plato "ensalada" no está en la carta. Prolog VII

  33. Evaluación del rendimiento del sistema statistics(+Concepto, -Valor) statistics. Devuelve el valor en uso del parámetro especificado o una relación completa de todos los parámetros time(+Objetivo) Devuelve el tiempo (en segundos) invertido, el número de inferencias realizadas y el LIPS (Logical Inferences Per Second) Prolog VII

  34. ?- statistics. 14.84 seconds cpu time for 2,196 inferences 1,449 atoms, 957 functors, 1,332 predicates, 21 modules, 22,169 VM-codes Limit Allocated In use Heap : 290,624 Bytes Local stack : 2,048,000 8,192 612 Bytes Global stack : 4,096,000 16,384 784 Bytes Trail stack : 4,096,000 8,192 240 Bytes Yes Prolog VII

  35. cputime (User) CPU time since Prolog was started in seconds inferences Total number of passes via the call and redo ports since Prolog was started. heap Estimated total size of the heap (see section 2.12.1.1) heapused Bytes heap in use by Prolog. heaplimit Maximum size of the heap (see section 2.12.1.1) local Allocated size of the local stack in bytes. localused Number of bytes in use on the local stack. locallimit Size to which the local stack is allowed to grow global Allocated size of the global stack in bytes. globalused Number of bytes in use on the global stack. globallimit Size to which the global stack is allowed to grow trail Allocated size of the trail stack in bytes. trailused Number of bytes in use on the trail stack. traillimit Size to which the trail stack is allowed to grow atoms Total number of defined atoms. functors Total number of defined name/arity pairs. predicates Total number of predicate definitions. modules Total number of module definitions. codes Total amount of byte codes in all clauses. Prolog VII

  36. Analizando el rendimiento o “Profiling” El analizador jerárquico de rendimiento fue introducido en la versión 5.1.10 de SWI-Prolog profile(:Objetivo) Ejecuta Objetivo como con time/1, recolecta las estadísticas de rendimiento y llama a show_profile(plain, 25). Con XPCE instalado esto provoca la apertura de una interfaz gráfica para mostrar los datos de rendimiento. profile(: Objetivo, +Estilo, +Número) Ejecuta Objetivo como con time/1. Reune las estadísticas de rendimiento y muestra las últimas Número de procedimientos en el stream de salida activo (ver show_profile/1) usando Estilo. Los resultados se conservan en la base de datos hasta que se invoca reset_profiler/0 o se llama a profile/3 y los resultados se muestran de nuevo con show_profile/1. Prolog VII

  37. show_profile(+Estilo, +N) Muestra los resultados reunidos por el analizador. Muestra los N procedimientos con mayor consumo de tiempo de CPU. Si Estilo es “plain” se muestra el tiempo empleado en los propios predicados. Si Estilo es “cumulative” se suma al tiempo de CPU empleado cada procedimiento el empleado por los procedimientos que se invocan desde éste. reset_profiler Conmuta el analizador a “false” y elimina las estadísticas. noprofile(+Nombre/+Aridad, ...) Declara el predicado Nombre/Aridad como invisible al analizador. El tiempo empleado en este predicado se suma al predicado que lo invoca al igual que el consumido por los predicados que se invocan desde él. Esto es particularmente útil con meta-predicados simples como call/1, ignore/1, catch/3, etc. Prolog VII

  38. findall_c_and_m(X,G,_):- asserta(found(mark)), call(G), asserta(found(X)), fail. findall_c_and_m(_,_,List):- collect_found([],L), !, List = L. collect_found(S,L):- getnext(X), !, collect_found([X|S],L). collect_found(L,L). getnext(X):- retract(found(X)), !, X \== mark. Versión de Clocksin & Mellish. % Esta poda es inútil ?- findall_c_and_m(X,member(X,[tom,dick,harry]),L). X = _G163 L = [tom, dick, harry] Yes ?- findall_c_and_m(X,member(X,[matthew,mark,luke,john]),L). X = _G166 L = [matthew, luke, john] Yes ?- listing(found). :- dynamic found/1. found(matthew). found(mark). Yes Prolog VII

  39. Versión 5 de Richard O’Keefe “The Craft of Prolog”. (Usa referencias de la base de datos) Versión 4 de Richard O’Keefe “The Craft of Prolog”. (Equivalente a la de C&M) findall_4(Template,Enumerator,List):- asserta('find all'([])), call(Enumerator), asserta('find all'({Template})), fail ; 'all found 4'([],List). 'all found 4'(SoFar, List):- retract('find all'(Item)), !, 'all found 4'(Item,SoFar,List). 'all found 4'([],List,List). 'all found 4'({Template},SoFar,List):- 'all found 4'([Template|SoFar],List). findall_5(Template,Enumerator,List):- asserta('find all'([]),MarkRef), ( call(Enumerator), asserta('find all'(Template)), fail ; 'all found 5'(MarkRef,[],List) ). 'all found 5'(MarkRef, SoFar, List):- clause('find all'(Item),_,Ref), !, erase(Ref), ( Ref = MarkRef -> SoFar = List ; 'all found 5'(MarkRef,[Item|SoFar],List) ). Prolog VII

  40. Versión 7 de Richard O’Keefe “The Craft of Prolog”. (Usa la base de términos) ¿Cuál será la más rápida? Este predicado genera N cláusulas del predicado item(test_time, N) Donde N es un entero comprendido en el intervalo [0,N) findall_7(Template,Enumerator,List):- recorda('find all',[],MarkRef), ( call(Enumerator), recorda('find all',Template,_), fail ; 'all found 7'(MarkRef,[],List) ). 'all found 7'(MarkRef, SoFar, List):- recorded('find all',Item,Ref), !, erase(Ref), ( Ref = MarkRef -> SoFar = List ; 'all found 7'(MarkRef,[Item|SoFar],List) ). %% ----------------------------------------- %% For testing %% ----------------------------------------- generate_items(0). generate_items(N):- P is random(1000), assert(item(test_time,P)), N1 is N-1, generate_items(N1). Prolog VII

  41. ?- generate_items(100000). Yes ?- time(findall(Precio,item(Verdura,Precio),L)). % 100,011 inferences, 1.38 CPU in 1.40 seconds (99% CPU, 72368 Lips) .... ?- time(findall_7(Precio,item(Verdura,Precio),L)). % 600,009 inferences, 2.58 CPU in 2.69 seconds (96% CPU, 232227 Lips).... .... ?- time(findall_4(Precio,item(Verdura,Precio),L)). % 400,007 inferences, 25.93 CPU in 26.19 seconds (99% CPU, 15428 Lips) .... ?- time(findall_5(Precio,item(Verdura,Precio),L)). % 600,009 inferences, 29.05 CPU in 30.02 seconds (97% CPU, 20653 Lips).... .... ?- time(findall_c_and_m(Precio,item(Verdura,Precio),L)). % 500,009 inferences, 87.69 CPU in 89.47 seconds (98% CPU, 5702 Lips).... (Sobre un P-II 233 MHz, Windows NT 4.0 SP6 y SWI-Prolog version 5.3.9 Prolog VII

  42. ?- generate_items(100000). Yes ?- time(findall(Precio,item(Verdura,Precio),L)). % 100,011 inferences, 1.38 CPU in 1.40 seconds (99% CPU, 72368 Lips) .... ?- time(findall_7(Precio,item(Verdura,Precio),L)). % 600,009 inferences, 2.58 CPU in 2.69 seconds (96% CPU, 232227 Lips).... ?- time(findall_4(Precio,item(Verdura,Precio),L)). % 400,007 inferences, 25.93 CPU in 26.19 seconds (99% CPU, 15428 Lips) .... ?- time(findall_c_and_m(Precio,item(Verdura,Precio),L)). % 500,009 inferences, 87.69 CPU in 89.47 seconds (98% CPU, 5702 Lips).... ?- time(findall_5(Precio,item(Verdura,Precio),L)). % 600,009 inferences, 29.05 CPU in 30.02 seconds (97% CPU, 20653 Lips).... (Sobre un P-II 233 MHz, Windows NT 4.0 SP6 y SWI-Prolog version 5.3.9) ?- generate_items(100000). Yes ?- time(findall(Precio,item(Verdura,Precio),L)). % 100,011 inferences in 0.37 seconds (269.911 Lips) .... ?- time(findall_7(Precio,item(Verdura,Precio),L)). % 600,009 inferences in 0.52 seconds (1.152.204 Lips) .... ?- time(findall_4(Precio,item(Verdura,Precio),L)). % 400,007 inferences in 3.73 seconds (107.374 Lips) .... ?- time(findall_c_and_m(Precio,item(Verdura,Precio),L)). % 500,009 inferences in 3.82 seconds (131.047 Lips) .... ?- time(findall_5(Precio,item(Verdura,Precio),L)). % 600,009 inferences in 4.41 seconds (136.170 Lips) .... (Sobre P-III 1GHz, W2000 y alguna versión anterior de SWI-Prolog) Prolog VII

  43. Prolog VII

  44. Prolog VII

  45. Prolog VII

  46. Prolog VII

  47. Verificación automática de código El paquete PlUnit en SWI-Prolog Permite definir procedimientos de verificación de predicados que pueden ejecutarse de forma muy sencilla para comprobar la corrección de éstos. Escribir procedimientos de verificación no debe considerarse como un “trabajo de programación extra”. Muy al contrario, su existencia dentro de un proyecto software se considera hoy en día como una medida de calidad del propio proyecto. Prolog VII

  48. Verificación automática de código (2) Un programa de test consiste en una serie de cláusulas Prolog encerradas entre las directivas begin_tests/1,2 y end_tests/1. Se pueden incluir dentro de un módulo Prolog o incluirse en un fichero dedicado. En este último caso, el fichero de test debe ocupar el mismo directorio y tener el mismo nombre que el fichero que contiene las definiciones que deben ser comprobadas, pero con la extensión .plt. El predicado load_test_files/1 puede cargar todos los ficheros de test relacionados con los ficheros fuente que hayan sido cargados (compilados) hasta ese momento. Prolog VII

  49. Verificación automática de código (3) Los puntos de arranque de un test se definen por las reglas test(Name) o test(Name, Options), donde Name debe ser un literal sin variables libres y Options son - evidentemente - una lista de opciones (ver manual). :- begin_tests(lists). :- use_module(library(lists)). test(reverse) :- reverse([a,b], [b,a]). :- end_tests(lists). Prolog VII

  50. Verificación automática de código (3) Verificación de predicados deterministas Son deterministas aquellos predicados que se verifican exactamente una vez, y - si están bien diseñados - no dejan alternativas. La función de test debe proporcionar argumentos de entrada y verificar los argumentos de salida. El test de verificación debe "verificarse" o emplear las opciones disponibles para los predicados test/2. Los dos ejemplos siguientes son equivalentes. El motor de verificación comprueba que el cuerpo del test no deja alternativas. Esto es fácilmente comprobable con el siguiente ejemplo: La segunda opción alerta al sistema que es conocido que member/2 deja alternativas. Prolog VII