2009-12-17 8 views
5

estoy contando el número de casos en una lista ...prólogo: la fijación de respuestas múltiples (usando corte?)

count(_,[],N,N). 
count(Elem,[Elem|List],N,M) :- !, N1 is N+1, count(Elem,List,N1,M). 
count(Elem,[_|List],N,M) :- count(Elem,List,N,M). 

Así, escribí esto de dos maneras en el prólogo, y trabaja la primera (arriba), pero tenía curiosidad por saber por qué el segundo no (o más bien, me dará respuestas múltiples, solo la primera es correcta) ¿por qué es esto?

muchas gracias

count(Z,X,R) :- count2(Z,X,R,0). 
count2(W,[H|T],L,A):- (W == H), Lnew is A+1, count2(W,T,L,Lnew). 
count2(W,[H|T],L,A):- count2(W,T,L,A). 
count2(W,[],A,A). 

Respuesta

0

Su pregunta incluye la respuesta ... el corte. El corte siempre tiene éxito y tiene el efecto secundario de "cortar" el árbol de derivación. Básicamente no puedes retroceder para pasar un corte.

El primer ejemplo ejecutará el corte si el objetivo se unifica con la segunda regla. En cierto sentido, esa elección se vuelve fija. Si hay una falla o retroceso después de que no haga clic sobre el corte, eliminando así múltiples respuestas. El corte es útil cuando las respuestas son mutuamente excluyentes. Es decir, cuando encuentre la primera respuesta, ninguna otra tendrá sentido.

+0

probé el segundo con un corte, entonces: cuenta (Z, X, R): - count2 (Z, X, R, 0). count2 (W, [H | T], L, A): -!, (W == H), Lnew es A + 1, count2 (W, T, L, Lnew). count2 (W, [H | T], L, A): - count2 (W, T, L, A). count2 (W, [], A, A). pero esto tampoco parece funcionar, entonces pensé que tal vez el código es fundamentalmente defectuoso de alguna manera –

-1

lo tengo!

aquí es una solución que funciona:

count(Z,X,R) :- count2(Z,X,R,0). 
count2(W,[H|T],L,A):- (W == H), !, Lnew is A+1, count2(W,T,L,Lnew). 
count2(W,[H|T],L,A):- count2(W,T,L,A). 
count2(W,[],A,A). 

Gracias Vicente - que me hizo revisar el corte!

+0

¿Una solución que funciona? ¡No! Observe los efectos perjudiciales de usar '(!)/0': aumenta la confianza de los programadores en que el código es correcto, mientras (al mismo tiempo) hace que el código se vuelva frágil/quebrantado más allá de cualquier posibilidad de reparación. – repeat

2

La razón por la cual su segundo intento produce múltiples soluciones es que la segunda cláusula count2 no impide que W y H tomen los mismos valores. Entonces, incluso si la primera cláusula de count2 tiene éxito, puede retroceder y tener éxito nuevamente en la segunda cláusula.

Puede arreglar esto usando un corte como dice Vincent Ramdhanie, o si prefiere evitar el uso de un corte, puede agregar una verificación explícita en la segunda cláusula para evitar que W y H se unan, como este:

count(Z,X,R) :- count2(Z,X,R,0). 
count2(W,[W|T],L,A):- Lnew is A+1, count2(W,T,L,Lnew). 
count2(W,[H|T],L,A):- W \= H, count2(W,T,L,A). 
count2(_,[],A,A). 

Además, tenga en cuenta que la primera cláusula count2 ahora usa la unificación implícita. En lugar de un control explícito. Esto es un poco más corto y más fácil de leer en mi opinión. A menos, por supuesto, que existiera una razón por la que usabas la igualdad en lugar de la unificación.