Como siempre, lo primero que hacemos es definir las pruebas que vamos a usar para realizar la aceptación de nnuestro programa, y un esqueleto vacío para ocurrencias/3, como para dejar feliz al intérprete de Prolog. La verdad es que no entiendo la restricción impuesta en el enunciado. Veamos si al ignorarla la podemos cumplir. Nos concentramos entonces en la solución del problema. En el predicado ocurrencias/3, tenemos los dos primeros argumentos de entrada y el tercero de entrada o de salida. ocurrencias(+atomo, +lista, ?lista_posiciones) Como cada vez que debemos resolver procesamiento de listas, pensemos como en Lisp. Se puede apreciar que el átomo que estoy buscando puede o no estar a la cabeza de la lista. Si estuviese a la cabeza de la lista, entonces la lista de posiciones debería tener un 1, que es la posición que ocupa la cabeza en cualquier lista. Si no estuviese, sencillamente debo buscar en la cola de la lista. Un esbozo de esto es: ocurrencias(X, [X|Xs], [1|Ys]) :- ... ocurrencias(E, [X|Xs], Ys) :- E \= X, ... Veamos el primer caso en detalle: ocurrencias(X, [X|Xs], [1|Ys]) :- ocurrencias(X, Xs, Ys). Pero si lo hacemos así, cada vez que X sea encontrado se pondrá un 1 en la lista de resultados, la cual al final tendrá tantos unos como veces aparecía X en la lista. Esto claramente no es lo que nos pedían, pero está bastante cerca. Lo que nos falta es que cada vez que ocurrencias/3 nos devuelva una lista de resultados, le sumemos uno a cada entero de dicha lista. Debemos sumar uno cuando encontramos X y cuando no lo encontramos, para que la cuenta sea correcta. O sea: ocurrencias(X, [X|Xs], [1|Zs]) :- ocurrencias(X, Xs, Ys), map_sume_uno(Ys, Zs). La definición de map_sume_uno/2 es trivial: map_sume_uno([], []) :- !. map_sume_uno([X|Xs], [Y|Ys]) :- Y is X + 1, map_sume_uno(Xs, Ys). Volvemos a ocurrencias/3. Ahora veremos el caso cuando el elemento que busco no está a la cabeza de la lista. Entonces podemos adaptar lo que ya tenemos: ocurrencias(E, [X|Xs], Zs) :- E \= X, ocurrencias(E, Xs, Ys), map_sume_uno(Ys, Zs). Nos queda pensar en el caso base. Como se puede ver en ambas cláusulas, el trabajo es cortar la lista que es el segundo argumento, la cual eventualmente se vaciará. Cuando se vacíe, ya no podrá hacerse concordar con ninguna de las cláusulas actuales pues ambas tratan de cortarle la cabeza, y eso falla con la lista vacía. Necesitamos una nueva cláusula. Si tengo una lista vacía, es claro que no importa cuál sea el elemento que busco, no podrá hallarse allí. En la semántica de nuestro ejercicio ---y esto puede verse en prueba_3--- cuando un elemento no está presente, el la lista de posiciones será vacía. Usemos esto para el caso base: ocurrencias(_, [], []) :- !. Entonces el resultado final nos queda: ocurrencias(_, [], []) :- !. ocurrencias(X, [X|Xs], [1|Zs]) :- !, ocurrencias(X, Xs, Ys), map_sume_uno(Ys, Zs). ocurrencias(E, [X|Xs], Zs) :- E \= X, ocurrencias(E, Xs, Ys), map_sume_uno(Ys, Zs). Note el cut en la segunda cláusula: si el elemento está en la cabeza de la lista, entonces es necesario que no se lo trate como que no está, para ello debo impedir que si se tuvo éxito en la segunda cláusula, en caso de fallo no se reintente la tercera. EOF ej-04.txt