2012-03-26 14 views
9
list_sum([], 0). 
list_sum([Head | Tail], TotalSum) :- 
    list_sum(Tail, Sum1), 
    Total = Head + Sum1. 

Este código devuelve true. Si reemplazo Total = Head + Sum1 con Total is Head + Sum1, devolverá el valor. Pero lo que debería reemplazarlo por conseguir el resultado como este:Suma de elementos en la lista en Prolog

?- list_sum([1,2,0,3], Sum). 
Sum = 1+2+0+3 ; % not to return value 6!!! 
+1

Al menos en SWI Prolog, por que para evaluar escribir 'total es Cabeza + Sum1' en lugar de utilizar el signo =' '. Las pistas para repensar esto para usar Tail Recursion Optimization son válidas, pero si solo estás tratando de aprender la Programación Declarativa no son esenciales, ya que es la debilidad de la Realidad que la verdadera programación declarativa no exista, y como tal Prolog as cualquier otro idioma adolece de debilidades, como el orden de evaluación de los procedimientos, que en este caso no es óptimo. – Matej

+0

"Este código devuelve verdadero." - ¿Para qué consulta? – ShiDoiSi

Respuesta

8

Nótese que en la segunda parte de su procedimiento TotalSum Nunca se instancia. Debería haber recibido una advertencia del intérprete al consultar su código.

aquí está mi sugerencia:

list_sum([Item], Item). 
list_sum([Item1,Item2 | Tail], Total) :- 
    list_sum([Item1+Item2|Tail], Total). 

La primera trata de la cláusula con el caso base, cuando sólo hay un elemento que queda en la lista, que es su resultado.

La segunda cláusula trata sobre el paso de recursión. Toma los primeros dos elementos de la lista y realiza una llamada recursiva reemplazando esos dos elementos con un nuevo término Item1 + Item2.

+0

¿No debería el caso base ser la lista vacía? – tjvr

+0

Primero, debe haber una asignación aritmética, 'is/2' en lugar de' + '. Y si la lista está vacía, fallará en lugar de devolver 0. – shybovycha

+0

@shybovycha: por favor, lea la pregunta nuevamente. OP quería obtener la expresión de la suma en 'Total', no la suma real. – gusbro

1

Si desea transformar una lista de números en una expresión aditiva, desde

[1,2,3] 

a

1 + 2 + 3

que podría hacer algo como esto, usando algo como una lista diferencia:

list_to_additive_expr([] , 0). 
list_to_additive_expr([X|Xs] , X + RHS) :- 
    sum_of(Xs , RHS). 

Como alternativa, puede utilizar un acumulador :

list_to_additive_expr(Xs , Expr) :- 
    list_to_additive_expr(Xs , 0 , Expr) 
    . 

list_to_additive_expr([]  , Expr , Expr) . 
list_to_additive_expr([X|Xs] , RHS , Expr) :- 
    sum_of(Xs , X + RHS , Expr) 
    . 

creo que se encuentra el primer estilo no es adecuadamente cola recursiva y así no conseguirá optimizado en un bucle a través de la optimización de recursión de cola (TRO) — y por lo tanto, si la lista es lo suficientemente larga, obtendrá un desbordamiento de la pila. El segundo enfoque debería tener TRO aplicado y debería funcionar para listas de cualquier longitud.

¿Qué es TRO, usted puede ser que pregunte? Aquí es Wikipedia with an answer for you:

En informática, una llamada de cola es una llamada a una subrutina que sucede dentro de otro procedimiento y que produce un valor de retorno, que luego se devuelve inmediatamente por el procedimiento de llamada . Luego se dice que el sitio de llamada está en posición de cola, es decir, al final de el procedimiento de llamada. Si una subrutina realiza una llamada de cola a sí misma, se llama recursivo de cola. Este es un caso especial de recursión.

Las llamadas de cola son importantes porque se pueden implementar sin agregar un nuevo marco de pila a la pila de llamadas. La mayor parte del marco del procedimiento actual no es necesario más, y puede ser reemplazado por el marco de la llamada final, modificado según corresponda (similar a la superposición para procesos, pero para llamadas a funciones). El programa puede saltar a la subrutina llamada.Producir dicho código en lugar de una secuencia de llamada estándar se llama eliminación de llamada de cola o optimización de cola de llamada.

+0

TRO se habla como TCO (Optimización de llamadas de cola) por lo general. – m09

19

La respuesta es sencilla:

sum_list([], 0). 
sum_list([H|T], Sum) :- 
    sum_list(T, Rest), 
    Sum is H + Rest. 

Este código funciona en una sola dirección - esto significa - no le permiten generar listas con esa suma específica. Pero dado que el conjunto de tales listas es infinito, eso no sería práctico de todos modos.

2

En Prolog (+)/2 es un operador binario infijo. Esto nos permite escribir A+B en lugar de +(A,B).

 
?- current_op(_,yfx,+). % left-associative binary infix operator 
true. 

(+)/2 asociados a la izquierda, por lo 1+2+3 es una abreviatura de (1+2)+3.

(.)/2 asociados a la derecha , por lo [1,2,3] es la abreviatura de .(1,.(2,.(3,[]))).

Para obtener parentización derecha, usamos un predicado auxiliar con un extra de "acumulador" argumento: consulta

list_sum([X|Xs],S) :- 
    list_sum0_sum(Xs,X,S). 

list_sum0_sum([], S ,S). 
list_sum0_sum([X|Xs],S0,S) :- 
    list_sum0_sum(Xs,S0+X,S). 

muestra:

?- list_sum([1,2,0,3],S). 
S = 1+2+0+3. 
1

El programa es

list_sum([],0). 

list_sum([Head|Tail], TotalSum):- 
list_sum(Tail, Sum1), 
TotalSum is Head+Sum1. 

ahora si la consulta es

?- list_sum([1,2,3,4], Sum). 

respuesta es

Sum = 10 
Cuestiones relacionadas