write sentencia salida reglas listas explicados entrada ejercicios datos consultas comandos string prolog predicate swi-prolog

string - sentencia - reglas en prolog



Predicados reversibles y cadenas en SWI-Prolog (4)

Como el predicado está trabajando en listas, me parece tentador usar DCG. Primero observemos que las cadenas en Prolog son realmente listas de códigos de caracteres:

?- X="test". X = [116,101,115,116]

Por supuesto, esto no es muy legible, así que veamos los personajes en sí mismos de sus códigos:

?- set_prolog_flag(double_quotes,chars). yes ?- X="test". X = [t,e,s,t]

Eso es mejor. Pensando en la relación que el predicado debería describir, opto por un nombre descriptivo como list_list_appended / 3. Este predicado tiene un objetivo: una regla dcg, llamémosla list_list // 2, que usa otra dcg, vamos a llamarla list // 2, para escribir realmente las listas:

list_list_appended(L1,L2,L3) :- phrase(list_list(L1,L2),L3). % L3 is L1+L2 list([]) --> % if the list is empty ... []. % ... there''s nothing in the list list([X|Xs]) --> % if there''s a head element ... [X], % ... it''s in the list list(Xs). % the tail is also a list list_list(L1,L2) --> % the list consists of ... list(L1), % ... L1 followed by ... list(L2). % L2

Tus consultas de ejemplo:

?- list_list_appended("test","auie","testauie"). yes ?- list_list_appended(L1,"auie","testauie"). L1 = [t,e,s,t] ? ; no ?- list_list_appended("test",L2,"testauie"). L2 = [a,u,i,e] ? ; no ?- list_list_appended("test","auie",L3). L3 = [t,e,s,t,a,u,i,e] ?- list_list_appended(L1,L2,"testauie"). L1 = [], L2 = [t,e,s,t,a,u,i,e] ? ; L1 = [t], L2 = [e,s,t,a,u,i,e] ? ; L1 = [t,e], L2 = [s,t,a,u,i,e] ? ; L1 = [t,e,s], L2 = [t,a,u,i,e] ? ; L1 = [t,e,s,t], L2 = [a,u,i,e] ? ; L1 = [t,e,s,t,a], L2 = [u,i,e] ? ; L1 = [t,e,s,t,a,u], L2 = [i,e] ? ; L1 = [t,e,s,t,a,u,i], L2 = [e] ? ; L1 = [t,e,s,t,a,u,i,e], L2 = [] ? ; no

Como usuario de SWI, también puede usar esta biblioteca en combinación con set_prolog_flag(double_quotes,chars). para obtener la salida en la forma deseada. Consulte esta respuesta para más detalles.

append/3 es un predicado muy poderoso. Supongamos que quiero un predicado que funcione de la misma manera pero para las cadenas de SWI-Prolog.

El enfoque más fácil que veo es transformar esas cadenas en listas con string_codes/2 , luego aplicar append/3 , luego use string_codes/2 . El gran problema con este enfoque es que string_codes/2 no funciona si las dos variables no están unificadas.

Esta es una solución extremadamente fea que se me ocurrió, que comprueba qué cadenas están unificadas para aplicar string_codes/2 cuando sea necesario:

append_strings(S1, S2, S3) :- nonvar(S1), nonvar(S2),!, string_codes(S1, A), string_codes(S2, B), append(A,B,C), string_codes(S3, C). append_strings(S1, S2, S3) :- nonvar(S1), nonvar(S3),!, string_codes(S1, A), string_codes(S3, C), append(A,B,C), string_codes(S2, B). append_strings(S1, S2, S3) :- nonvar(S2), nonvar(S3),!, string_codes(S2, B), string_codes(S3, C), append(A,B,C), string_codes(S1, A). append_strings(S1, S2, S3) :- nonvar(S3), string_codes(S3, C), append(A,B,C), string_codes(S1, A), string_codes(S2, B).

Esto produce los resultados correctos para los siguientes casos:

?- append_strings("test","auie","testauie"). true. ?- append_strings("test",A,"testauie"). A = "auie". ?- append_strings(A,"auie","testauie"). A = "test" ; false. ?- append_strings(A,B,"testauie"). A = "", B = "testauie" ; A = "t", B = "estauie" ; A = "te", B = "stauie" ; A = "tes", B = "tauie" ; A = "test", B = "auie" ; A = "testa", B = "uie" ; A = "testau", B = "ie" ; A = "testaui", B = "e" ; A = "testauie", B = "" ; false.

¿Realmente no hay forma de hacer las cosas más simples que esto? Supongamos que quiero crear un montón de predicados que funcionen con cadenas de caracteres como lo harían con las listas: obviamente no quiero tener que escribir lo que hice para append/3 para todas ellas. Pero tampoco quiero trabajar con cadenas de código porque entonces no tengo forma de saber si estoy manipulando una lista normal o realmente una cadena.


Esta es una definición más compacta:

append_strings(S1, S2, S3):- append_strings1(S1, L1, [1]-[], N1), append_strings1(S2, L2, [1|N1]-N1, N2), append_strings1(S3, L3, [1,1|N2]-N2, N3), (N3/=[_,_|_] ->instantiation_error(append_strings/3); true), append(L1, L2, L3), (ground(S1)->true;string_codes(S1, L1)), (ground(S2)->true;string_codes(S2, L2)), (ground(S3)->true;string_codes(S3, L3)). append_strings1(S, L, G-NG, N):- (ground(S) -> (string_codes(S, L), N=G) ; N=NG).

Comprueba si cada argumento se basa y trata de convertirlo a códigos, luego verifica si el tercer argumento está en tierra o si los otros dos son, y arroja un error de instanciación si las condiciones no se cumplen.

Después de anexarlo, se convierte de nuevo a argumentos de cadena que no están molidos.


Solo use string_concat / 3. Como ISO atom_concat / 3, se puede usar en muchos modos, incluyendo (-, -, +).


ha habido una pregunta similar hace algún tiempo, mostraré mi propuesta, revisada

:- meta_predicate when_(0). when_(P) :- strip_module(P,_,Q), Q =.. [_|As], or_list(As, Exp), % hurry debugging :-) display(Exp), when(Exp, P). or_list([A], ground(A)) :- !. or_list([A|As], (ground(A);Exp)) :- or_list(As, Exp). append_strings(S1, S2, S3) :- maplist(when_, [string_codes(S1, A), string_codes(S2, B), append(A,B,C), string_codes(S3, C)]).

Si está interesado, puedo agregar un operador para ocultar los detalles de la sintaxis, para obtener algo como

append_strings(S1, S2, S3) -:- string_codes(S1, A), string_codes(S2, B), append(A,B,C), string_codes(S3, C).