¿Qué estructuras de control alternativas útiles conoce? [cerrado]

12

La pregunta similar se cerró en SO.

A veces, cuando estamos programando, encontramos que alguna estructura de control en particular sería muy útil para nosotros, pero no está disponible directamente en nuestro lenguaje de programación.

¿Qué estructuras de control alternativas crees que son una forma útil de organizar el cálculo?

El objetivo aquí es obtener nuevas formas de pensar acerca de estructurar el código, a fin de mejorar la fragmentación y el razonamiento.

Puede crear una sintaxis / semántica deseada que no está disponible ahora o citar una estructura de control menos conocida en un lenguaje de programación existente.

Las respuestas deben dar ideas para un nuevo lenguaje de programación o para mejorar un lenguaje real.

Piensa en esto como una lluvia de ideas, así que publica algo que creas que es una idea loca pero que puede ser viable en algún escenario.

Se trata de la programación imperativa.

    
pregunta Maniero 28.11.2010 - 17:11

22 respuestas

14

Bien, esta es una pregunta divertida.

También me gustaría tener un else general para while y para bucles, para cuando la condición no sea verdadera en la prueba first :

while (condition) {
    // process
}
else {
    // condition was never true
}

Esto evita el recálculo incómodo de la condición o el almacenamiento en una variable.

    
respondido por el Macneil 28.11.2010 - 18:07
10

¿Por qué no mezclar algunas respuestas en una?

while (expr) {

    // Executed every iteration, unless first{} is present.
    // May be explicitly called rest{} if you like first{} to come first.

    // Blocks may return results, and consequently be used in expressions.
    return expr;

} first {

    // Executed only on the first iteration.

} pre {

    // Executed before every iteration.

} post {

    // Executed after every iteration.

} catch (oops) {

    // All blocks are implicitly try{}ed if followed by a catch{}.

} finally {

    // Executes after the block completes, regardless of exceptions.

} else {

    // Executed if the loop body or rest{} never executes.

} never {

    // Executes only when a client is present.

} drop (bad, worse), // Explicitly ignore certain exceptions.
  until (expr);      // Here, have a post-body condition, too.

Una sintaxis de construcción extensible y generalizada de control de flujo en un lenguaje imperativo sería bastante útil y entretenida. Hasta que aparezca, supongo que solo usaré Lisp o algo así.

    
respondido por el Jon Purdy 28.11.2010 - 23:00
7

Estructuras de control como funciones.

Quiero que for , if , else , while , etc. sean funciones, no estructuras especiales.

Quiero que return , try/except y goto sean derivados de continuaciones.

Esto, por supuesto, tiene menos que ver con una estructura de control particular y más con la forma en que se ven las estructuras de control en general, el meta de las estructuras de control.

    
respondido por el dietbuddha 29.11.2010 - 10:12
6

El artículo vinculado definitivamente entiende bien sobre N + 1/2 Loops de Donald Knuth. Expresado en C / C ++ / Java:

for (;;) {
  get next element;
  if (at the end) break;
  process the element;
}

Esto es útil para leer líneas o caracteres de un archivo, probar si has alcanzado EOF y luego procesarlo. Estoy tan acostumbrado a ver el patrón for(;;)..if(..)break; que es idiomático para mí. (Antes de leer el artículo de Knuth, reimpreso en el libro Literate Programming , este solía ser un "wtf?".)

Knuth sugirió las palabras clave loop/while/repeat :

loop:
  S;
while C:
  T;
repeat

Donde S y T son titulares de una serie de cero o más declaraciones, y C es una condición booleana. Si no hubiera una declaración S , sería un bucle while, y si no hubiera una declaración T , sería un bucle do.

Esta construcción en sí misma podría generalizarse permitiendo cero o más cláusulas while C , lo que la hace perfecta para expresar bucles infinitos y luego algunas condiciones más raras que necesitarían dos comprobaciones.

En el mismo artículo, Knuth sugirió un mecanismo de señalización que sería una versión local de excepciones de lanzamiento / captura (como alternativa al uso de goto).

para mi? Deseo que Java sea compatible con la optimización de llamadas de cola, para poder expresar cualquier estructura de control general según sea necesario.

Actualización: olvidé mencionar que muchos programadores de C / C ++ / Java solucionan este problema mediante el uso de una asignación incorporada en la condición de while :

while ((c = getc(f)) != -1) {
   T;
}

Usando los términos del constructo de Knuth, esto está permitido cuando S y C se pueden combinar en una sola expresión. Algunas personas odian ver la tarea incrustada arriba, mientras que otras odian ver el break en el for (;;) anterior. Pero cuando S y C no se pueden combinar, como cuando S tiene múltiples declaraciones, el for (;;) es la única alternativa sin repetir el código. La otra alternativa es simplemente duplicar el código S :

S;
while (C) {
  T;
  S;
}

La alternativa loop/while/repeat de Knuth parece mucho mejor.

    
respondido por el Macneil 28.11.2010 - 17:41
6

El lenguaje BCPL tenía una valueof expresión que se podría usar para activar una secuencia de declaraciones en una sola expresión:

foo(a, b, valueof {some series of statements; resultis v});

Donde some series of statements puede ser cualquier cosa y todo valueof se evalúa como v .

Esto podría ser útil en Java para cuando necesite calcular un argumento para llamar a this() o super() (lo que requiere que no suceda nada antes). Por supuesto, usted podría escribir un método separado, pero eso podría ser una molestia si necesita pasar muchos valores locales para el contexto.

Si puede usar final para las variables que se necesitan, ya puede hacer un valueof en Java usando clases internas anónimas:

foo(a, b, new Object(){String valueof(){
    String v ...; some series of statements; return v;}}.valueof());
    
respondido por el Macneil 28.11.2010 - 18:24
6
unless(condition) {
  // ...
}

hace lo mismo que:

if(!condition) {
  // ...
}
repeat {
  // ...
} until(condition)

hace lo mismo que:

do {
  // ...
} while(!condition)
    
respondido por el missingfaktor 28.11.2010 - 18:21
5

En otra nota, me gustaría ver un mejor soporte para los iteradores en lenguajes de programación. En particular, para cuando quiera bajar dos colecciones en pares :

for (String s, Integer i : stringsSet, integersSet) {
    // use the pair (s, i)
}

Es posible que algunos idiomas dinámicos ya tengan esto, o que se admitan fácilmente a través de bibliotecas y macros, pero creo que esto está en el espíritu de su pregunta.

Si los dos conjuntos no son del mismo tamaño, entonces podría lanzar una excepción o podría tener un else después del bucle para señalar que hubo una diferencia en los tamaños.

Naturalmente, podría generalizar esto para bajar tres o más listas.

Actualización: También sería útil hacer el producto cartesiano entre iterables:

for (String s, Integer i : stringsSet * integersSet) {
    // use the pair (s, i), each s with each i
}

que no sería más que bucles anidados:

for (String s : stringsSet) {
    for (Integer i : integersSet) {
        // use the pair (s, i), each s with each i
    }
}

Me preocupa un poco que entre las dos notaciones que he proporcionado aquí haya una diferencia de O (n) y O (n ^ 2) en el número de pares, con solo el cambio de un solo carácter.

    
respondido por el Macneil 28.11.2010 - 18:05
5

Hay el llamado "Bucle de Dijkstra" (también llamado "Bucle protegido de Dijkstra"). Se definió en The Guarded Command Language (GCL) . Puede encontrar información sobre la sintaxis y la semántica en el artículo de Wikipedia anterior en la sección 6 Repetición: hacer .

Hoy en día, conozco un lenguaje de programación que soporta este control de forma directa. Es Oberon-07 (PDF, 70 KB). Y es compatible con "Dijkstra's Loop" en la forma de la sentencia while. Eche un vistazo a la sección 9.6. Mientras que las declaraciones en el PDF anterior.

WHILE m > n DO m := m – n 
ELSIF n > m DO n := n – m 
END

P.S. Esta es una copia de mi respuesta SO .

    
respondido por el Wildcat 29.11.2010 - 19:15
4

Expresiones de estilo de icono con retroceso integrado.

Python obtiene muchos de los beneficios del generador de iconos, y hace un mejor trabajo en general, IMO. Y en principio, el retroceso fue solo una especie de tiro de excepción, pero fue la simplicidad de las expresiones el equivalente aproximado de ...

x = (a / b) else c;

para manejar casos de falla como división por cero.

Donde el icono se volvió loco - no hay operadores de comparación con devolución de valores booleanos. Las comparaciones siempre tuvieron éxito o activaron el retroceso, y hubo otro problema semántico que ahora estoy tratando de recordar desesperadamente de que ... bueno, digamos que probablemente esté más reprimido que olvidado.

Siempre pensé que deberían tener una expresión if sin otra parte - if (condition, success-value) tipo de cosas, retroceder si la condición devuelve falso - y eliminar las comparaciones extrañas.

EDIT Recuerdo, realmente obvio. Una comparación con dos argumentos tiene éxito o falla, no calcula un nuevo valor para devolver. Entonces, cuando tiene éxito, ¿qué devuelve ? Respuesta - uno de los argumentos. Pero si escribe a > b , ¿cuál es el argumento lógico para devolver - a o b ? ¿Y qué pasa si escribes b < a en su lugar? Pienso que siempre devolvió el argumento correcto, lo que tiene tanto sentido como cualquier otra cosa, pero aún así, por lo general, me pareció el argumento equivocado.

    
respondido por el Steve314 29.11.2010 - 00:58
4

Esto es solo una idea general y una sintaxis:

if (cond)
   //do something
else (cond)
   //do something
also (cond)
   //do something
else
   //do something
end

La condición TAMBIÉN siempre se evalúa. ELSE funciona como siempre.

Funciona para el caso también. Probablemente es una buena manera de eliminar la declaración de ruptura:

case (exp)
   also (const)
      //do something
   else (const)
      //do something
   also (const)
      //do something
   else
      //do something
end

se puede leer como:

switch (exp)
   case (const)
      //do something
   case (const)
      //do something
      break
   case (const)
      //do something
   default
      //do something
end

No sé si esto es útil o simple de leer, pero es un ejemplo.

    
respondido por el Maniero 02.12.2010 - 12:56
3

Estilo de aprobación de aprobación viene a la mente. Luego, por supuesto, también le gustaría tener Tail Call Optimization .

    
respondido por el pillmuncher 28.11.2010 - 19:44
3

Ramificación de subprocesos sin problemas, tiene una sintaxis como una función, pero se ejecuta en un subproceso independiente y no puede acceder a los datos que no se le han pasado inicialmente.

branch foo(data, to, be, processed){
    //code
    return [resulting, data]
}

Cuando se llama a una rama, inmediatamente devolverá un identificador.

handle=foo(here, is, some, data)

El identificador se puede usar para verificar si la tarea se realizó.

handle.finished() //True if the execution is complete

Si el resultado se solicita antes de que se complete la ejecución, el hilo principal simplemente esperará.

[result, storage]=handle.result()

Esto no cubriría los escenarios de subprocesos múltiples más avanzados, sino que proporcionaría una forma fácilmente accesible de comenzar a utilizar múltiples núcleos.

    
respondido por el aaaaaaaaaaaa 29.11.2010 - 22:22
3
if (cond)
   //do something
else (cond)
   //do something
else (cond)
   //do something
first
   //do something
then
   //do something
else (cond)
   //do something
else
   //do something
end
Los bloques

FIRST y THEN se ejecutan si cualquiera de los 3 condicionales se evalúa como verdadero. El bloque FIRST se ejecuta antes del bloque condicional y THEN se ejecuta después de que se haya ejecutado el bloque condicional.

ELSE escritura condicional o final después de las instrucciones FIRST y THEN son independientes de estos bloques.

Se puede leer como:

if (cond)
   first()
   //do something
   then()
else (cond)
   first()
   //do something
   then()
else (cond)
   first()
   //do something
   then()
else (cond)
   //do something
else
   //do something
end


function first()
   //do something
return
function then()
   //do something
return

Estas funciones son solo un formulario para leer. Ellos no crearían alcance. Es más como un gosub / return de Basic.

Utilidad y legibilidad como asunto de discusión.

    
respondido por el Maniero 01.12.2010 - 13:52
2

A veces me encuentro escribiendo un bucle que necesita hacer algo diferente durante la primera iteración. Por ejemplo, mostrando < th > etiquetas en lugar de < td > etiquetas.

Yo manejo esta situación con una bandera booleana. Algo como esto:

first = true

while (some_condition)
    if (first)
        do_something
        first = false
    else
        do_something_else

Parece tonto comprobar el valor de first en cada iteración cuando será falso la mayor parte del tiempo.

Me gustaría tener una opción de bucle para especificar un cuerpo de bucle diferente en la primera iteración. No habría necesidad de una variable separada. El código compilado tampoco necesitaría uno, porque el código generado tendría dos cuerpos, uno para la primera iteración y otro para el resto.

    
respondido por el Barry Brown 28.11.2010 - 18:59
1

[copiado de mi propia respuesta en stackoverflow]

ignoring - Para ignorar las excepciones que ocurren en un determinado bloque de código.

try {
  foo()
} catch {
  case ex: SomeException => /* ignore */
  case ex: SomeOtherException => /* ignore */
}

Con una construcción de control que ignora, puedes escribirla de manera más concisa y más fácil de leer como:

ignoring(classOf[SomeException], classOf[SomeOtherException]) {
  foo()
}

[Scala proporciona esto (y muchas otras construcciones de control de manejo de Excepciones) en su biblioteca estándar, en el paquete util.control. ]

    
respondido por el missingfaktor 28.11.2010 - 18:24
1

En lugar de:

switch(myEnum) {
  case MyEnum.Val1: do1(); ...
  case MyEnum.Val2: do2(); ...
....

Hazlo en Python, o ahora también en C #:

action = val2func[myEnum]
action()

Scala tiene muchas características nuevas.

Finalmente, los idiomas como Clojure se pueden ampliar para proporcionar la funcionalidad adicional.

    
respondido por el Job 29.11.2010 - 05:27
1

Tengo dos ideas.

A menudo encuentro que estoy repitiéndome en catch blocks. Esto puede ayudarse de alguna manera a través de la extracción de métodos, pero puede causar un desorden innecesario si los métodos son muy cortos o no son dignos de un método. Por lo tanto, sería bueno anidar catch blocks:

try {
    // Save something
} catch (Exception e) {
    // Something we do for all Exceptions
    catch (ProcessingException e) {
        // Something we do for all Processing exceptions
        catch (DBExcpetion e) {
            // DBExceptions are a subclass of ProcessingException
        }
        catch (BusinessRuleException e) {
            // BusinessRuleExceptions are also a subclass of ProcessingException
        }
    }
    // Something we do after specific sub class Exceptions
 }

En la programación web, a menudo también me encuentro haciendo algo como esto (esto no es un ejemplo real, así que no analices casos ficticios):

Account a = getSavedAccount();
if (a == null) {
    a = getAccountFromSessionId();
}
if (a == null) {
    a = getAccountFromCookieId();
}
if (a == null) {
    a = createNewAccount();
}

En Javascript (bueno, ECMAScript, y quizás otros con los que no estoy familiarizado), ya que cualquier valor puede evaluarse como una condición, || puede ayudar.

var a = getAFromLocation1() || getAFromLocation2() || default;

Realmente me gusta cómo se ve, y deseo que haya más idiomas, en particular en el lado del servidor, que tengan soporte para eso. (PHP puede evaluar cualquier cosa como una condición, pero convierte la expresión condicional completa en un valor booleano en lugar de preservar el valor. No sé acerca de Python o Ruby). de los tres casos, es posible que también tenga un mal diseño de software.

    
respondido por el Nicole 29.11.2010 - 19:13
1

El interruptor generalizado ha dicho más arriba:

 switch(x){
  predicate1:
     dosomething();
  predicate2:
     dosomethingelse();
 }

En Haskell:

  switch' :: a -> [(a -> Bool, b)] -> b
  switch' a [] = undefined
  switch' a (f,b):xs = if f a
                     then b
                      else switch' a xs
    
respondido por el John John 29.11.2010 - 23:15
0

En C # me gustaría usar switch () { ... } simple, pero ampliable con tales expresiones:

switch (value)
{
  // string-based operators:
  case begins "Maria": // to catch Maria Carey
    break;
  case ends "Washington": // to catch George Washington
    break;
  case like "ph": // to catch Phil, Phillip, Sophie
    break;
  case between "Aaron" and "April": // to catch all names between
    break;

  // use non-static variables in case expression:
  case Dao.GetDefaultBabyName():
    break;

  // continuable cases without breaking
  case "John":
    bonus = 25;
  case "Peter":
    salary = 500;
    break;

  // jumps between cases
  case "Aleron":
    // do something
    break;
  case "Bella":
    // do something
    jump "Aleron";
    break;

}

Y así sucesivamente. Lo mismo con números u otros tipos (que admiten IComparable , IConvertible , ...)

Esto podría hacer que mi código sea más lacónico y legible.

    
respondido por el Genius 29.11.2010 - 16:08
0

Es una pregunta divertida, como dijo @Macneil.

Mi estructura de control inusual favorita, que descubrí (tos humilde), es ejecución diferencial .

Tiene ciertos usos. Para mí, el uso abrumador es la programación de interfaces de usuario, que es una instancia del problema más general de mantener datos redundantes en la correspondencia. Por un lado, hay datos de aplicación, y por otro lado, hay controles de UI que deben mantenerse de acuerdo. Esto suena como "vinculante" pero en realidad hay mucho más que eso.

Usualmente lo implemento por macros en C o C ++. En C # tengo que hacerlo a mano las declaraciones de expansión. Eso es un dolor, pero funciona.

Una vez lo implementé en términos de macros de Lisp, y luego estuvo muy limpio. No requirió cuidado por parte del programador. Podría haber hecho lo mismo en cualquier otro lenguaje estructurado si me hubiera tomado la molestia de escribir un analizador completo y luego generar todo lo correcto. Es un gran proyecto, y no lo he hecho.

    
respondido por el Mike Dunlavey 29.11.2010 - 21:00
0

Las estructuras de control "tradicionales" como for tratan sobre controlar al hombre trabajador, manteniéndolo sometido a las ideologías corruptas de la élite capitalista gobernante. Es por eso que uso estructuras de control alternativas como ph0r en su lugar. Es como for , pero más radical: no verás a ph0r vistiendo traje y corbata, soltando algunos BS corporativos. ph0r lo mantiene real, hombre.

¡Lucha contra el poder!

    
respondido por el j_random_hacker 30.11.2010 - 09:18
0

Más simple for loop-

for(100)
{
    //Will run for 100 times
}


for(i)
{
    //Will run for i times while i must be a positive integer
}


for(i as a)
{
    //Will run for i times while i must be a positive integer
    //and a is the incremental loop variable starting from 0 and 
    //scoped within the loop
}


for(i as a=2)
{
    //Will run for i times while i must be a positive integer
    //and a is the incremental loop variable starting from 2 and 
    //scoped within the loop
}
    
respondido por el Gulshan 31.12.2010 - 09:58

Lea otras preguntas en las etiquetas