Cómo hacer recursión en un sistema de reescritura inspirado en L-sistemas, sin DCG.
Estoy tratando de escribir un pequeño sistema de reescritura recursiva inspirado en el Sistema L de Aristid Lindenmayer, básicamente para aprender Prolog así como para pensar en conceptos generativos en Prolog. Me gustaría lograr esto sin DCG. Debido a los efectos secundarios del predicado inicial generate.
y output
, no es una idea de Prolog 100% pura. No dudes en descomponer el concepto.
Mi principal problema está al final de la lista. Hacer coincidir la regla para cada elemento de la lista original y crear una nueva lista con el resultado de cada sustitución.
[a]
El axioma se convierte en [a,b]
se convierte en [a,b,a]
y así sucesivamente. O mejor aún como una lista de listas [[a,b],[a]]
para mantenerlo más flexible y comprensible, ¿y luego aplanarlo más adelante?
Un ejemplo básico sin constantes, que se podría agregar de manera similar. El axioma se utiliza solo una vez al principio. La idea es codificar el nombre o símbolo de la regla a intercambiar y los símbolos con los que se debe intercambiar, como un hecho/relación. Comenzar con generate.
lo repetiría 20 veces con un contador.
% Las reglas
axiom(a, [a]).
rule(a, [a, b]).
rule(b, [a]).
% Comienza el programa
generate :-
axiom(a, G),
next_generation(20, G).
% Repetirlo hasta que el contador sea 0.
next_generation(0, _) :- !.
next_generation(N, G) :-
output(G),
linden(G, Next),
succ(N1, N),
next_generation(N1, Next).
% Concatena la lista en una cadena para la salida
output(G) :-
atomic_list_concat(G,”,C),
writeln(C).
% Aquí estoy atascado, la búsqueda y el intercambio recursivo.
% ¿Cómo intercambio cada elemento con la sustitución correspondiente en una nueva lista?
linden([],[]). % La lista vacía devuelve lista vacía.
linden([R],Next) :- % Lista con solo un elemento, p. e., el axioma
rule(R, Next). % Busca la regla y devuelve la lista para intercambiar la corriente.
linden([H|T], Next) :- % Si hay más de un elemento en la lista original,
rule(H,E), % busque la regla para el Encabezado/Elemento de lista actual
% ????? % Concatene el resultado con el resultado de los elementos anteriores
linden(T, Next). % Recursión hasta que se procese la lista original.
% Una vez hecho esto, devuelve la nueva lista a next_generation/2
davy.ai
Solución
Para crear la nueva lista con la sustitución de cada elemento en la lista original, puede utilizar el predicado
maplist/3
incorporado. Este predicado aplica un predicado dado a cada elemento de una lista y crea una nueva lista con los resultados.Primero, debe modificar el predicado
linden/2
para aplicar la regla de sustitución a cada elemento en la lista. Esto se puede hacer utilizandomaplist/3
de la siguiente manera:El predicado
aplicar_regla/2
aplica la regla al elemento si hay una regla definida para ese elemento, de lo contrario solo devuelve el elemento en sí.Luego, en el predicado
next_generation/2
, puede reemplazar la llamada alinden/2
con una llamada al predicadolinden/2
actualizado:Esto aplicará la regla de sustitución a cada elemento en la lista y creará una nueva lista con los resultados.
Finalmente, para mantener la nueva lista como una lista de listas, puede modificar las definiciones de Axioma y regla:
Esto define el Axioma y las reglas como una lista de listas, donde cada elemento de la lista representa una rama separada.
Con estas modificaciones, el programa debería poder crear y mostrar una nueva lista con la sustitución de cada elemento en la lista original.
También tenga en cuenta que el predicado
generate/0
no es seguro, ya que utiliza el predicadowriteln/1
, que es una operación de IO que puede fallar. Para hacerlo seguro, puede reemplazarlo con el predicadoformat/2
, que devuelve verdadero independientemente de la operación de salida. Por ejemplo:En este caso, el predicado
format/2
se utiliza para mostrar la lista de listas como una cadena, que luego se puede analizar más tarde para recrear la lista de listas.