list - Implementar el predicado de miembro como una sola línea
prolog dcg (3)
Pregunta de la entrevista!
Así es como normalmente se define la relación de member
en Prolog:
member(X, [X|_]). % member(X, [Head|Tail]) is true if X = Head
% that is, if X is the head of the list
member(X, [_|Tail]) :- % or if X is a member of Tail,
member(X, Tail). % ie. if member(X, Tail) is true.
Defínelo usando una sola regla.
Solución:
member(X, [Y|T]) :- X = Y; member(X, T).
Demostración:
?- member(a, []). fail. ?- member(a, [a]). true ; fail. ?- member(a, [b]). fail. ?- member(a, [1, 2, 3, a, 5, 6, a]). true ; true ; fail.
Cómo funciona:
- Estamos buscando una aparición del primer argumento,
X
, en el segundo argumento,[Y|T]
. - Se supone que el segundo argumento es una lista.
Y
coincide con su cabeza,T
coincide con la cola. - Como resultado, el predicado falla para la lista vacía (como debería).
- Si
X = Y
(es decir,X
se puede unificar conY
), entonces encontramosX
en la lista. De lo contrario (;
) comprobamos siX
está en la cola.
- Estamos buscando una aparición del primer argumento,
Observaciones:
- Gracias al humilde café por señalar que el uso de
=
(unificación) produce un código más flexible que el uso de==
(pruebas de igualdad). Este código también se puede usar para enumerar los elementos de una lista dada:
?- member(X, [a, b]). X = a ; X = b ; fail.
Y se puede usar para "enumerar" todas las listas que contienen un elemento dado:
?- member(a, X). X = [a|_G246] ; X = [_G245, a|_G249] ; X = [_G245, _G248, a|_G252] ; ...
Reemplazar
=
por==
en el código anterior lo hace mucho menos flexible: fallaría inmediatamente en elmember(X, [a])
y causaría un desbordamiento de pila en elmember(a, X)
(probado con SWI-Prolog versión 5.6. 57).
- Gracias al humilde café por señalar que el uso de
Ya que no especificaste qué otros predicados podemos usar, voy a intentar hacer un poco de trampa. :P
member(X, L) :- append(_, [X|_], L).
newmember(X, Xs) :-
phrase(( ..., [X] ),Xs, _).
Con
... --> [] | [_], ... .
En realidad, la siguiente definición también asegura que Xs
es una lista:
member_oflist(X, Xs) :-
phrase(( ..., [X], ... ), Xs).