Saltar al contenido

¿Cómo volver a “repetir” en Prolog?

Nuestro team de redactores ha estado mucho tiempo investigando soluciones a tu búsqueda, te brindamos la resolución y nuestro deseo es servirte de gran apoyo.

Repetir

repeat/0 se define simplemente como:

repeat.
repeat :- repeat.

O equivalente:

repeat :- true ; repeat.

Para repetir, debe retroceder hasta el repeat llamar al fallar, ya sea explícitamente con fail oa través de otro predicado fallido (ver ejemplo en el enlace anterior).

...
repeat,
...,
fail.

Una vez que desee salir del patrón repetido, puede (y debe) cortar ! el árbol de decisiones para que no tengas una repeat punto de elección. Si no lo hace, el intérprete aún tendrá la posibilidad de retroceder hasta repeat más tarde.

NB: las reglas para !/0 se puede encontrar aquí.

Ejemplo

Para tu ejemplo específicamente, eso significa (por cierto, yo uso writeln):

test :- 
  nl,
  writeln('Welcome.'),
  repeat, 
  writeln('Print this message again? (yes/no)'),
  read(Ans),nl,
  (Ans == yes -> 
    writeln('You selected yes.'), 
    fail % backtrack to repeat
  ; writeln('You selected no.'),
    ! % cut, we won't backtrack to repeat anymore
  ).

Otras observaciones

Observe que OP usó átomos, mientras que las cadenas son suficientes. De hecho, los átomos (comillas simples) tienen hash y se prefieren para el razonamiento simbólico, mientras que las cadenas (comillas dobles) no se internan y son más adecuadas para mostrar mensajes.

Con el mismo espíritu, al leer, prefiero usar read_string(end_of_line,_,S), que lee hasta el final de la línea y devuelve un string. Con read/1, Tuve que cerrar el flujo de entrada con Ctrl + D, lo cual fue molesto.

Además, podemos deshacernos de -> completamente:

test :- 
  nl,
  writeln("Welcome."),
  repeat, 
  writeln("Print this message again? (yes/no)"),
  read_string(end_of_line,_,Ans),
  nl,
  write("You selected "),
  write(Ans),
  writeln("."),
  Ans == "no", % Otherwise, repeat
  !.

Eliminando -> Podría ser controvertido ver cómo otras personas discuten acerca de tener más casos. Aquí está el fundamento: dado que la pregunta original parece ser una tarea sobre repeat, las partes sobre el manejo yes, no y los insumos incorrectos explícitamente parecen estar subespecificados y, francamente, no son realmente relevantes. Mantuve la semántica original y fusioné el yes y casos de entrada incorrecta: después de todo, ¿qué sucede cuando el usuario dice yes? repetimos, exactamente como cuando un usuario escribe una entrada inesperada. El único caso en el que no repeat es cuando Ans == no.

Ahora, si queremos cambiar el comportamiento del código original para verificar explícitamente todos los tipos de entradas posibles, aquí hay un intento:

test :- 
  nl,
  writeln("Welcome."),
  repeat, 
  writeln("Print this message again? (yes/no)"),
  read_string(end_of_line,_,Ans),
  nl,
  (memberchk(Ans,["yes","no"]) ->
    write("You selected "),
    write(Ans),
    writeln("."),
    Ans == "no",
    !
  ; writeln("Bad input" : Ans),
    fail).

Por qué no intentas hacer:

test :- 
     nl, write('Welcome.'), 
     nl, test_internal.

test_internal :- 
     write('Print this message again? (yes/no)'), nl,
     read(Ans), nl,
     (    Ans == yes 
     ->   write('You selected yes.'), nl, test_internal
     ;    Ans == no, write('You selected no.'), !
     ;    test_internal
     ).

EDITAR

Si no puede separar el predicado en dos, otra solución (use el volcado de memoria uno) podría ser:

test :- 
     nl, write('Welcome.'), 
     repeat, nl,
     write('Print this message again? (yes/no)'), nl,
     read(Ans), nl,
     (    Ans == yes 
     ->   write('You selected yes.'), fail
     ;    Ans == no, write('You selected no.'), !
     ;    fail
     ).

Editar: alternativa usando if-then y diseño diferente

Para aumentar aún más la legibilidad, (->)/2 (if-then-ELSE-FAIL) se puede utilizar (consulte la sección del manual de SWI-Prolog sobre predicados de control). Además, un diseño diferente de la cascada if-then-else puede ayudar.

test :- 
     nl, write('Welcome.'), 
     repeat, nl,
     write('Print this message again? (yes/no)'), nl,
     read(Ans), nl,
     (    Ans == yes -> write('You selected yes.'), fail
     ;    Ans == no  -> write('You selected no.'),  !
     ).

Tenga en cuenta que el uso de if-then-ELSE-FAIL no es estrictamente necesario; se podría usar una conjunción. Sin embargo, su uso facilita la adición de código que maneja casos adicionales (maybe, i_dont_know, i_m_afraid, i_gotta_go) en el futuro.

Al final de todo puedes encontrar las explicaciones de otros creadores, tú además tienes la habilidad mostrar el tuyo si lo crees conveniente.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)


Tags :

Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *