Probabilidad de while while vs for loop

8

Tengo este profesor, es bastante inteligente (a veces, jaja), dijo que los buenos programadores intentan usar whilebucles en lugar de forbucles. La razón que dio para esto es porque los whilebucles se pueden probar, ya que en uno se puede explicar completamente lo que sucede en un whilebucle, mientras que no se puede hacer eso para un forbucle. También dijo algo sobre los programadores de la NASA que solo usan whilebucles y no se les permite hacer forbucles debido a esto.

Me cuesta mucho entender esto, para ambos bucles uno puede explicar cómo funcionan en detalle, ¿verdad? para ambos siempre sabrás lo que va a pasar?

¿Alguien puede explicarme por qué whilese pueden probar los bucles (y por eso, podría ser mejor que los forbucles, en algunos casos al menos).

EDITAR:
tal vez se refería a:
2: Todos los bucles deben tener un límite superior fijo. Debe ser trivialmente posible que una herramienta de verificación demuestre estáticamente que no se puede exceder un límite superior preestablecido en el número de iteraciones de un bucle. Si el enlace de bucle no puede probarse estáticamente, la regla se considera violada.

Aunque esto todavía no dice nada sobre la diferencia entre while y for loops.

Vincent
fuente
17
Tu maestro está completamente equivocado o has informado mal de lo que dijo de alguna manera. Esta razón para preferir formás whilesimplemente no tiene sentido. Puede haber uno, pero este no lo es.
Kilian Foth
77
Estoy de acuerdo con Kilian. No tiene sentido que debe haber una diferencia, ya que for (init; test; step) { body }tiene un desugaring trivial while: {init; while (test) { step; body }}.
1
Para (;;) {cout << "realmente no son tan diferentes" << endl;}. La mayor diferencia es que para los bucles le permite mantener fácilmente una variable (i) en el alcance del bucle.
Nathan Cooper
2
@MikeNakis por el contrario. Un artesano de carga no haría la pregunta, solo perpetuaría mitos. Quizás incluso castigar a otros por no "adherirse a la regla".
sehe
2
@ MikeNakis No sé si tenemos suficiente información para evaluar la mentabilidad del maestro.
sehe

Respuestas:

13

En pocas palabras : lo que su maestro probablemente quiso decir es que la semántica de whilees más o menos la misma en la mayoría de los idiomas, mientras que la semántica de forpuede cambiar considerablemente (vea la discusión a continuación). Por lo tanto, las pruebas independientes del lenguaje abstracto son más confiables con a while, pero se debe tener cuidado de que una prueba con un forbucle no coincida con la semántica del forbucle en muchos idiomas.

Su pregunta no es lo suficientemente precisa (aunque puede que no sea su culpa).

El punto es que, afaik, no hay un estándar oficial, compatible con ISO, o una definición de referencia fory whilebucles aceptados oficialmente . La definición depende del lenguaje de programación.

Por lo tanto, no puede hacer ninguna declaración general con respecto a su equivalencia antes de haber definido exactamente lo que cada uno puede hacer. Me refiero a eso más precisamente, ya que es uno de los principales argumentos utilizados en otras respuestas (y la discusión será útil en lo que sigue).

Sobre intertranslatabilidad de fory whilebucles

Resumen : depende del lenguaje de programación, pero siempre es posible siempre que pueda tener un bucle infinito y una forma de salir de él.

Pero puede hacer tal declaración para un lenguaje de programación específico, y la respuesta dependerá de las características del lenguaje.

Eso también significa que no hay pruebas generales, sino solo una para cada lenguaje de programación.

Una cosa que generalmente es cierta es que un whilebucle generalmente puede imitar un forbucle, porque el bucle while puede hacer la prueba de condición de salida del bucle for, realizar la inicialización de la variable de control con una asignación antes de ingresar al bucle y hacer el incremento al final del cuerpo del bucle, para que

for i from 1 by 2 to 10 do { xxx }

se convierte

i=1
while i≤11 do { xxx; i←i+2 }

Esto funciona más o menos para la mayoría de los idiomas, pero no es tan obvio como parece, y puede haber muchos "detalles" de los que preocuparse.

Por ejemplo, en muchos idiomas, el forbucle evalúa 3 argumentos (valor inicial, incremento y valor final) como argumentos estrictos , evaluados una vez antes de ingresar al bucle, mientras que otros tomarán luego como argumentos thunk para ser reevaluados en cada turno, o posiblemente como argumento perezoso para ser evaluado solo cuando sea necesario.

Otro punto puede ser que la variable de incremento puede ser local al forbucle, o tener que ser una variable local de la función donde aparece el bucle.

Dependiendo de tales problemas, la traducción de a fora a whilepuede variar ampliamente, aunque generalmente es posible lograrlo.

Lo mismo vale para lo contrario, traduciendo a whileen un forbucle.

El primer problema es que un whilebucle siempre reevaluará la condición de salida en cada vuelta. Pero algunos forbucles no proporcionan una condición que se reevalúa en cada turno, aparte de la comparación de la variable de control con algún valor fijo calculado en la entrada del bucle. Entonces la traducción no es posible a menos que exista algún otro medio para salirse del ciclo en algunas condiciones arbitrarias.

Esto se puede lograr con varios dispositivos, generalmente comenzando con una declaración condicional que pruebe la condición, seguida de un salto implementado, según esté disponible, por una declaración de salida del ciclo, una declaración de retorno (después de encapsular el ciclo en una función), una declaración goto o un aumento de excepción.

En otras palabras, nuevamente depende mucho de los idiomas, y posiblemente de las características sutiles de los idiomas.

Esto dice, como respondió @milleniumbug , la intertranslación es fácil en el lenguaje C, porque un forlopp es esencialmente un whilebucle más algo extra para una variable de control incrementada.

Pero esto no se aplica necesariamente a otros idiomas, y muy probablemente no de la misma manera.

Dicho esto, generalmente se supone que los lenguajes de programación tienen poder de Turing con solo uno de estos bucles, ya que todo lo que necesita es un bucle infinito. Entonces, siempre y cuando tenga alguna forma de bucle para siempre, y posiblemente decida detenerse, está bastante seguro de que puede imitar cualquier otra construcción ... pero no necesariamente fácil.

En cuanto a las pruebas

Resumen : No conozco ninguna razón para afirmar que las pruebas deberían ser significativamente más difíciles con una u otra (a menos que alguna característica extraña del lenguaje).

Probablemente hay un malentendido, o tu maestro tenía su mente en otra cosa.

La semántica formal se puede definir para los diversos tipos de bucles definidos en los lenguajes de programación, y luego usarse para probar propiedades.

Puede ser, nuevamente según el idioma, que la realización de pruebas formales con respecto a los programas puede ser más compleja en algunos casos. Pero eso depende del idioma.

No puedo imaginar una razón por la cual las pruebas deberían ser significativamente más difíciles con una construcción más que con la otra. El forciclo puede ser más complejo ya que puede ofrecer, como en C, todo lo que se hace con un whileplus más. Pero si lo hicieras con un while, tendrías que agregar los extras en alguna otra forma.

Podría usar el argumento general formal de intertranslatabilidad, siempre y cuando exista la posibilidad de un solo bucle infinito. Sin embargo, me abstendré de hacer eso, ya que las construcciones involucradas no son nada con lo que quieras lidiar en una prueba, y claramente sería una declaración injusta, al menos en la práctica.

Sin embargo, siguiendo la discusión anterior, hemos visto que las dificultades para la intertranslatabilidad provienen de la gran variabilidad del forciclo de un idioma a otro. De ahí la siguiente conclusión, que probablemente sea la respuesta correcta:

Una posibilidad para comprender la afirmación de su maestro es que la semántica del whilebucle es prácticamente la misma en todos los lenguajes de programación, mientras que la sintaxis y la semántica del forbucle pueden variar significativamente de un idioma a otro. Por lowhilefor tanto, es posible hacer pruebas "abstractas" generales con bucles que tienen una semántica independiente del lenguaje en buena medida, mientras que esto no es posible para el bucle que tiene una sintaxis y una semántica que cambian demasiado de un idioma a otro. Pero esto no se aplica dentro de un lenguaje dado, cuando la semántica de ambos se define con precisión.

Mi mejor sugerencia es que le preguntes a tu maestro qué quiso decir exactamente y si puede darte un ejemplo. Frases o malentendidos es un evento común.

babou
fuente
1
@VincentAdvocaat Bueno, el sitio es para todos los usuarios, no solo el Cartel original de la pregunta. Por eso lo hice. También marqué mi propia respuesta para que el moderador la detuviera si era incorrecta. En realidad, fue una pregunta interesante, y me llevó algo de tiempo llegar a mi conclusión ... esperando que sea la correcta. Háganos saber si se entera.
babou
Acabo de notar la edición que hiciste hace una hora agregando lo que dices en tu respuesta aquí, esta es de hecho la mejor respuesta posible a mi pregunta y te lo agradezco. En lo que respecta a la atención del moderador, es más culpa mía crear un duplicado entre múltiples sitios de SE. Entonces, para eso no veo ninguna razón para eliminar esta respuesta, si algo debe eliminarse, debería ser la segunda pregunta que hice, pero como su respuesta está bien formulada y explica la declaración hecha aquí en profundidad, no creo que sea sabio para eliminar cualquiera de los dos. a menos que agregue la información a esta pregunta.
Vincent
1
No tengo idea, suceden cosas extrañas, siempre es divertido cuando la gente no explica ninguna razón para esto.
Vincent
3
Sucedió nuevamente: 1 arriba + 1 abajo. Lo que me molesta es que está dañando el sitio más que yo. Trato de escribir respuestas completas que ayuden a las personas. Si tiene la culpa, sería más prudente comentar para darme la oportunidad de corregir. Si es por alguna otra razón, solo reduce el atractivo de una respuesta que podría ser útil, a expensas del sitio. Me pregunto si reemplazar con la respuesta extendida o eliminar el descargo de responsabilidad al final tiene algo que ver con eso. Pero el moderador parecía estar de acuerdo con la situación.
babou
1
Como moderador, me gusta su respuesta y aprendí algo al leerla. Es una buena respuesta
maple_shaft
12

En el lenguaje C puede reescribir cada forciclo a un whileciclo equivalente y viceversa.

while -> for transformación:

Volver a escribir

while(condition) { instructions; }

a

for(; condition; ) { instructions; }

for -> while transformación:

Esto es un poco más complicado, especialmente si tiene una continuedeclaración en su ciclo.

Volver a escribir:

for(init; condition; next) { instructions; }

a:

{
    init;
    while(condition)
    {
        instructions;
    next_label:
        next;
    }
}

pero reemplace cada continue;declaración con goto next_label;declaración. Si conditiones una instrucción nula, reemplácela con true.

Como puede ver, en el lenguaje C ninguno de los dos es más "demostrable" (lo que sea que eso signifique) que el otro, ya que incluso si uno de los bucles lo fuera, podría reescribirlo en términos de otro bucle.

Ahora, existen otros idiomas donde esta while <-> forequivalencia no existe. Por ejemplo, en Pascal, puede asumir más sobre el forciclo. Esto significa que no puede expresar cada concepto al escribir un forbucle, pero puede probar más sobre el flujo del código:

for i:=1 to n do
    instructions;

Aquí, nse guarda al comienzo del ciclo, por lo que los cambios nno influyen en el recuento de iteraciones, y no se puede modificar ien el cuerpo del ciclo. Esto significa que puede probar trivialmente que este ciclo finalmente terminará (como nes finito, y no puede modificarlo i).

milleniumbug
fuente
Reescribir algunos bucles "for" como "while" requeriría duplicación de código, agregar banderas o agregar goto. Si se agregan banderas, todos los demás bucles se pueden emular usando un solo "while (1) ..." alrededor de una función que se ejecuta hasta un "retorno"; si uno agrega "goto", todos los otros bucles se pueden emular usando eso.
supercat
Gracias por probar mi punto. Copiar y pegar el fragmento de código A no cambia mi capacidad de razonar al respecto.
milleniumbug
De hecho, copiar / pegar no cambia la capacidad de razonar sobre el código, pero en mi humilde opinión es una razón importante para no considerar "para" como una construcción de lenguaje superflua, ya que uno de los objetivos de diseño de un buen lenguaje de programación debería ser minimizar La necesidad de copiar / pegar.
supercat
7

En la lógica de Floyd-Hoare , el sistema formal más común para razonar sobre la corrección de los programas de computadora, existe la regla while .

En palabras, si tiene una cláusula de protección (la expresión entre paréntesis en el while()), una función variante (una expresión con valores discretos que se puede mostrar que disminuye monotónicamente cada vez que se ejecuta el bucle, y siempre es positiva), y un bucle invariante (una declaración lógica que siempre es verdadera antes y después de cada vez que se ejecuta el ciclo), puede probar que el ciclo while finalizará (porque la función variante no puede seguir disminuyendo) y que eventualmente la cláusula de protección será falsa y el ciclo invariante sea cierto.

La lógica de Floyd-Hoare no tiene reglas para los forbucles o cualquier construcción que los lenguajes reales puedan tener.

Sin embargo, como explican otras respuestas, los bucles for siempre se pueden escribir en términos de bucles while. Eso significa que se puede razonar sobre ellos, solo requiere un poco más de trabajo.

Si su maestro tenía cursos en la universidad donde tenía que proporcionar pruebas de corrección de sus programas, probablemente escribía programas utilizando solo bucles while. Sé que lo hice. Y una vez que estás acostumbrado a pensar en términos de guardias y funciones variantes e invariantes de bucle, parecen muy naturales. El uso excesivo de los bucles es un hábito que ves con los graduados de CS, tuve que aprender a dejar de hacerlo en mis primeros meses como desarrollador profesional.

En algún momento, su maestro recordaba todo esto como "buenos programadores usan bucles while", mientras que lo que realmente sucede es más como "algunos graduados de CS convierten sus hábitos de prueba de corrección en hábitos prácticos de programación".

RemcoGerlich
fuente
Esto parece ser bastante consistente con mi propia evaluación, aunque basada en una opinión diferente. La lógica de Floyd-Hoare no tenía ninguna razón para considerar el forciclo, que no tiene una definición fija y es más complejo, sin ser formalmente necesario.
babou
3

En realidad, en cierto sentido, todo lo contrario es cierto.

Un lenguaje con solo forbucles no es completo de Turing, solo puede calcular las funciones primitivas-recursivas, no todas las funciones computables de Turing. Dado que todos los cálculos en un lenguaje con solo forbucles siempre terminan, el problema de detención y todos los demás problemas de decidibilidad basados ​​en él, simplemente no surgen, por lo que es posible decidir mecánicamente muchas más propiedades estáticas de los programas que en un lenguaje con whilebucles

OTOH, un lenguaje con solo números naturales, una sola variable y while-loops es Turing-complete, por lo que no es posible decidir incluso las propiedades más simples: ¿este programa devolverá un resultado?

Jörg W Mittag
fuente
1
Un forlenguaje único puede producir un whilecomportamiento equivalente al disminuir la variable de bucle (suponiendo que el lenguaje lo permita) durante las iteraciones que no se supone que den como resultado una terminación. (Por ejemplo for n in 1 to 2 { if condition then n := n-1 })
Blrfl
Hay muchas formas en que se puede hacer que un bucle for se repita para siempre, dependiendo, por supuesto, de su definición en el idioma en cuestión. Y un bucle infinito es suficiente para completar Turing.
babou
@babou: La interpretación más común de un bucle for es un bucle que itera sobre un rango o colección finita. Por supuesto, en muchos idiomas puedes hackear un bucle for para que se comporte como un bucle while, pero creo que eso no es lo que Jörg tenía en mente.
Giorgio
0

Me gustaría decir que, en realidad, no hay diferencia. Su pregunta es irrelevante. Puede ser que tu maestro haya querido usar while-loop cuando no. de iteraciones no se conoce de antemano. En muchos casos necesitamos usar un ciclo while para extraer dígitos de un no. cuando el usuario ingresa el no. que puede ser de cualquier longitud. Técnicamente hablando, la similitud entre el bucle for & while es que ambos son bucles controlados por entrada en los que la (expresión / condición de prueba) se evalúa antes de ingresar al cuerpo del bucle. Esta es la distinción entre los bucles while y do-while.

Jai Thakur
fuente
-1

Probablemente proviene de la programación inicial de C donde, según las normas actuales, los bucles fueron ampliamente abusados ​​y mal utilizados, especialmente la modificación condicional. A medida que los programadores comenzaron a comprender el efecto que tenían ciertos estilos de programación, el abuso y el mal uso de los condicionales de bucle cayeron en desgracia, y la declaración, aunque (posiblemente) una vez válida, ya no tiene ninguna verdad.

La declaración no tiene absolutamente ninguna verdad si observa únicamente la definición y la sintaxis del lenguaje e ignora cómo se estaba utilizando.

Sin embargo, la declaración en sí ofrece una valiosa lección a cualquiera que quiera entenderla, su historia y por qué ya no se considera verdadera. - ¿Cuál es la expresión sobre el aprendizaje, los errores y repetirlos .....

Mattnz
fuente
-10

¡Tu profesor tiene razón!

La razón es la siguiente es válida C

for (int x = 1 ; x < 20 ; x++ ) {
   x = x + 9;
}

¡No puede garantizar que las variables de condición no hayan sido manipuladas!

James Anderson
fuente
2
¿Cómo eso hace que los whilebucles funcionen mejor aquí?
milleniumbug
77
¿Oh si? Mientras que, con los whilebucles, ¿puede garantizar que la variable de condición no haya sido alterada? De hecho, la manipulación de la variable de condición es la única forma de salir de un whilebucle. Por lo general, me abstengo de votar negativamente, pero por esta respuesta, haré una excepción.
Mike Nakis
James, ¿podrías explicar por qué esto no es tan problemático para los bucles while? Puede que te encuentres con algo, sin embargo, la gente parece estar en desacuerdo con una laguna de pruebas contrarias en el caso de los bucles while
Vincent
1
@VincentAdvocaat Diría que con un ciclo while esperas que la variable de condición se altere de alguna manera, mientras que un ciclo for espera que se cambie solo en la parte del paso de la construcción del ciclo for. Este principio de mínimo asombro es más importante de lo que muchos creen en la programación.
gbjbaanb
3
@gbjbaanb es cierto, pero en lo que respecta a la pregunta, está muy lejos del principio del menor asombro a la demostrabilidad.
Mike Nakis