2011-05-16 36 views
5

Necesito hacer esta tarea con prolog (sabor SWI) y no puedo entender algunas cosas.Prolog, lista de construcciones con cláusulas condicionales

Por ejemplo, si quiero iterar a través de una lista y agregar sus elementos a otra, pero SÓLO si cumplen con ciertas condiciones, ¿cómo lo haré? Puedo agregarlos todos, o ninguno, pero si agrego una cláusula que comprueba esta condición, la recursividad completa resulta ser "falsa". Entiendo por qué es esto, pero no tengo idea de cómo solucionarlo. Básicamente lo que quiero es:

goal(Stuff) :- do_something(X), 
       only_do_this_if_something(Y), 
       always_do_this(Z). 

Actualmente, si only_do_this_if_something(Y) falla, también resultan always_do_this(Z) duerma como a toda la meta se vuelve falsa ...

+2

+1 por ser honesto sobre la necesidad de ayuda para la tarea asignada. – csl

+0

posible duplicado de [Prolo bucles y declaraciones condicionales?] (Http://stackoverflow.com/questions/3964420/prolog-loops-and-conditional-statements) –

+1

@GuyC: Aquí no hay nada específico para SWI. – false

Respuesta

8

puede utilizar la estructura if:

<condition> -> (do_something) ; (do_something else) 

en este caso:

goal(Stuff):- 
    do_something(X), 
    if_something(Y)-> do_this(Y) ; true, 
    always_do_this(Z). 

o simplemente escribir dos cláusulas como:

goal(Stuff):- 
    do_something(X), 
    conditional_stuff(Y), 
    always_do_this(Z). 

conditional_stuff(Y):- 
    condition(Y), 
    do_this(Y). 

conditional_stuff(_). 
+0

Gracias, la primera parte de este mensaje resolvió el problema bastante bien. – n00bist

0

probar el ignorar/1 predicado:

goal(Stuff) :- 
    do_something(X) 
    ignore(only_do_this_if_something(Y)), 
    always_do_this(Z). 

ignorar/1 llama al único argumento y tiene éxito siempre que falle o no:

ignore(X) :- X, !. 
ignore(_). 
1

Compruebe el siguiente patrón de programación, que se utiliza bastante en Prolog:

  • Iterar a través de la lista, un elemento a la vez
  • Establecer un caso base para la recursividad
  • En una cláusula, comprobar si son aplicables las condiciones y hacer algo, y luego continuar con la recursividad
  • En la cláusula siguiente omita la elemento y continuar con la recursión

Tiene que utilizar el corte (!) para prohibir el rastreo posterior o comprobar explícitamente que la condición no se aplica en la última cláusula.

Tenga en cuenta que usted dijo que quería tener una lista de salida con los elementos para los que 'algo' aplicado (que no es lo que escribió en su código) ...

La aplicación de este modelo a su problema se sería algo como esto:

myRecursion([], []). % This is the base case 
myRecursion([Item|Tail], [Item|NTail]):- 
    something_applies(...), 
    do_something(...), 
    only_do_this_if_something(...), 
    always_do_this(...). 
    myRecursion(Tail, NTail). 
myRecursion([Item|Tail], NTail):- 
    not(something_applies(...)), 
    do_something(...), 
    always_do_this(...), 
    myRecursion(Tail, NTail). 
+0

-1. Esto es complicado y propenso a errores debido a la repetición, y es completamente innecesario ya que Prolog tiene una construcción if-then-else. –

+1

Estoy completamente en desacuerdo con usted;) Creo que es mucho más claro tener cláusulas separadas para acciones separadas. La primera parte del cuerpo de cada cláusula distingue entre casos y luego simplemente haces lo que quieras hacer en el resto de la cláusula. Intenta comprender un fragmento de código con un par de construcciones if-then-else y creo que estarás de acuerdo conmigo. Sin embargo, está bien usar algunos if-then-elses aquí y allá si no afectan la legibilidad. – gusbro

+0

Uso regularmente el constructo if-then-else y creo que contribuye en gran medida a la claridad * y * de mi código. Su significado lógico es más claro que el de corte, mientras que mantiene el principio DRY en comparación con su estilo. –

1

Si he entendido bien, entonces lo que necesita es un predicado como include/3: examp

include(:Goal, +List1, ?List2) 
    Filter elements for which Goal succeeds. True if List2 contains 
    those elements Xi of List1 for which call(Goal, Xi) succeeds. 

Uso LE:

?- include(number, [a(b), 2, _, 1.2, C, '1'], L). 
L = [2, 1.2]. 

Ahora su tarea se convierte en "la forma de aplicar include/3". Una vez que haya implementado su versión de include/3, puede verificar si coincide con la versión de SWI mirando su código fuente: listing(include).