Julia: mini julepe: si x entonces y

Creado en 16 may. 2016  ·  53Comentarios  ·  Fuente: JuliaLang/julia

En varias discusiones, se ha sugerido permitir sintaxis como:

if x then y

Como declaración abreviada "si" y como alternativa a la común:

x && y

sintaxis que aprovecha el operador de cortocircuito && para ejecutar condicionalmente y (donde y a menudo contiene otros efectos secundarios y no necesariamente devuelve un Bool ).

Las principales ventajas de esta construcción if-then son: un código más legible, que depende menos del abuso de && e incluye formalmente un formulario de declaración "si" que no requiere un end palabra clave.

Se me ocurrió el otro día que esta sintaxis también proporcionaría un medio conveniente para implementar #550, que se vería así:

A = [if x % 2 == 0 then f(x) for x in 1:10]

Confiando en el hecho de que if-then no requiere una palabra clave end , que probablemente necesitaríamos de alguna forma, incluso si usáramos guardias de estilo python:

A = [f(x) for x in range(10) if x % 2 == 0]

Para ser claros, la sintaxis de la guardia de Julia esencialmente estaría haciendo una reescritura de:

A = [if x % 2 == 0 then f(x) for x in 1:10]

a

A = [Filter(x->x % 2 == 0, f(x) for x in 1:10)]

También como una nota aclaratoria, esto permitiría la sintaxis de guardia en el nivel de _generador_ en lugar de solo el nivel de _comprensión_ (que también coincide con lo que permite Python).

julep

Comentario más útil

Tal vez estoy en la minoría ya que otros idiomas han adoptado este enfoque, pero siempre he encontrado que la acción que viene antes de la condición es realmente extraña, por ejemplo, println("positive") if x > 0 . Supongo que es más conciso que if x > 0 println("positive") end pero al menos para mí tiene el costo de la legibilidad.

Pienso en ello como una conversación:

Julia: "Imprimiré una cadena..."
Haroldo: "¡Impresionante!"
Julia: "... pero solo si se cumple alguna condición".
Harold: "Ay. :("

versus

Julia: "Si se cumple alguna condición, imprimiré una cadena".
Harold: "Está bien, genial".

Todos 53 comentarios

La sintaxis del modificador if/for estilo Perl/Ruby parece que se combinaría mejor con esto. En otras palabras:

println("positive") if x > 0         # conditional execution
x^2 for x=1:100                      # generator
[ x^2 for x=1:100 ]                  # comprehension
x^2 if x % 3 == 0 for x = 1:100      # filtered generator
[ x^2 if x % 3 == 0 for x = 1:100 ]  # filtered comprehension

También tiene la ventaja de tener un precedente en otros idiomas, que la sintaxis if - then sin end no parece tener.

Solo una nota al margen sobre la gestión de problemas: # 6823 discutió exactamente este problema. En algún momento se cerró sin comentarios, seguí preguntando por qué se cerró porque claramente no había habido un consenso para cerrarlo, pero nunca obtuve una respuesta. Parece que sería más eficiente no cerrar problemas como el #6823, de lo contrario, estas discusiones irán en círculos y todos los puntos del problema original se repetirán nuevamente. Probablemente hubiera tenido sentido cambiar el título de #6823 en algún momento y luego agregar esto aquí.

Sí, buen punto. De hecho, #6823 parece estar en medio de la discusión y probablemente no debería haberse cerrado.

Tal vez estoy en la minoría ya que otros idiomas han adoptado este enfoque, pero siempre he encontrado que la acción que viene antes de la condición es realmente extraña, por ejemplo, println("positive") if x > 0 . Supongo que es más conciso que if x > 0 println("positive") end pero al menos para mí tiene el costo de la legibilidad.

Pienso en ello como una conversación:

Julia: "Imprimiré una cadena..."
Haroldo: "¡Impresionante!"
Julia: "... pero solo si se cumple alguna condición".
Harold: "Ay. :("

versus

Julia: "Si se cumple alguna condición, imprimiré una cadena".
Harold: "Está bien, genial".

@ararslan : no estoy en desacuerdo, que es una de las razones por las que esta característica no está en Julia a pesar del estado de la técnica en Ruby y Perl. Sin embargo, se combina mucho mejor con la sintaxis del modificador for para generadores y comprensiones, razón por la cual lo mencioné aquí.

@StefanKarpinski Sí, de acuerdo, encaja mejor con eso. Sin embargo, todavía estoy irremediablemente apegado a las condiciones que preceden a las acciones. :smile: (Pero como me he encontrado diciendo a menudo últimamente, mi opinión realmente no importa; solo soy un tipo).

Supongo que si tuvieras algo como

if x % 3 == 0 then x^2 for x = 1:100

entonces no está claro de inmediato que está iniciando una comprensión/generador/thingamajig, porque también se lee como si se pudiera agrupar como

if x % 3 == 0 then (x^2 for x = 1:100)

es decir, si alguna condición entonces generador. no me importaría

if x % 3 == 0 x^2 end for x = 1:100            # More obvious what's happening, IMO
filter(x -> x % 3 == 0, [x^2 for x = 1:100])   # Verbose, but... ¯\_(ツ)_/¯

Supongo que si la condición fuera seguir la acción en un generador, creo que preferiría una palabra clave diferente a if , por ejemplo where . Luego se lee casi como una consulta SQL, por ejemplo

x^2 for x = 1:100 where x % 3 == 0

Creo que where deja un poco más claro que está filtrando los valores de x producidos por for que if .

Me parece más agradable que los datos fluyan en una sola dirección, aunque en este caso de derecha a izquierda en lugar de izquierda a derecha.

¿Puedes explicar qué quieres decir con eso?

El for 1:n "genera" valores, el if x % 3 == 0 los filtra y el x^2 los transforma: los generadores ya fluyen de derecha a izquierda y para mantener ese flujo, el filtro debe ir en el medio. Si la cláusula if va a la derecha de la cláusula for , entonces los datos "fluyen" desde el centro hacia el extremo derecho y luego hacia el extremo izquierdo, lo cual es extraño. Si la cláusula if está a la izquierda, los datos "fluyen" desde el extremo derecho hasta el extremo izquierdo y el centro. Sé que SQL coloca la cláusula where a la derecha de los nombres de las tablas y las expresiones a la izquierda, porque se parece más al inglés, pero siempre me ha parecido molesto leer esto y creo que leerlo en inglés no es una heurística que deba llevarse demasiado lejos en el diseño de lenguajes de programación.

Cosas que no me gustan de if x then y :

  1. Presenta la nueva palabra clave then .
  2. Es más corto escribir if x y end que if x then y ; x && y es aún más corto.
  3. La palabra clave then se usa ampliamente en idiomas para el tipo de sintaxis exactamente opuesto: una sintaxis multilínea if que requiere una palabra clave end (o fi en bash , asco).

Oh, sí, ahora veo lo que quieres decir sobre el flujo. Eso tiene sentido. ¡Gracias por la explicación!

¿Sería raro poder hacer

x^2 if x % 3 == 0 for x = 1:100

y _no_ poder hacer

println("positive") if x > 0

?

Todos los buenos puntos.

De hecho, me gusta mucho la sintaxis que @StefanKarpinski propuso por primera vez en su primer comentario. Estoy principalmente interesado en tener generadores condicionales, con una forma abreviada más general _if_-form como bonificación.

Con respecto a los generadores, estaba leyendo if (o where - no tengo opinión al respecto) para ser parte del rango... está creando un iterador x = 1:10 if/where x % 2 == 0 , que luego se combina con la expresión de la izquierda para crear un Array (o generador).

En cierto sentido, x = 1:10 where x % 2 == 0 es en sí mismo un generador de algún tipo de iterable. Esta podría ser una sintaxis independiente, ¿no?

Siento que el filtrado es de alguna manera una operación diferente a la declaración condicional if a then b . El filtrado actúa sobre el rango de iteración. Cuando el if a then b se combina con la expresión a la izquierda del generador, esperaría que emitiera nothing en los casos en que a fuera false . Compare lo que sucede lógicamente si agrego corchetes:

[(x^2 if i % 2 == 1) for i = 1:10] # [nothing, 4, nothing, 16, nothing, 36, nothing, 64, nothing, 100]
[x^2 (for i = 1:10 where i % 2 == 0)] # [4, 16, 36, 64, 100]

Tomando los ejemplos de @ararslan , si lo permitimos

println("positive") if x > 0

entonces en mi humilde opinión se deduce que

x^2 if x % 3 == 0 for x = 1:100

probablemente debería emitir nothing, nothing, 9, nothing, nothing, 36, ...

Finalmente, si tuviéramos que adoptar un condicional abreviado if , mi voto es por la condición antes de la declaración, por las razones descritas en la primera publicación de @ararslan , siendo el principio de menor sorpresa al leer el código. (recuerde, si dicen que el código se lee más que se escribe, entonces if a then b es mejor sintaxis que a && b incluso si este último es más corto). También significa que los dos tipos posibles de if dentro del generador serían distintos: en el extremo izquierdo, con la expresión, o en el extremo derecho, con el rango.

En cuanto a la tradición en Ruby/Perl, creo que es mejor intentar encontrar la mejor solución en lugar de atascarse en la tradición. Si funciona y se siente natural, a la gente le gustará.

Además, si tenemos if/where en rangos, ¿debemos tener cuidado para asegurarnos de que el rango se mantenga cartesiano para los generadores multidimensionales?

# Make a circular array (filled with distance to center)
r = 5
[sqrt(x^2 + y^2) for x = -5:5, y = -5:5 where x^2 + y^2 <= r^2]

¡Esto es un poco genial y un poco horrible!

Siento que el filtrado es de alguna manera una operación diferente a la instrucción condicional si a entonces b.

¡Sí! Estaba a punto de publicar este mismo comentario. El filtrado opera en el iterador como un todo y no es parte de la expresión calculada en su interior.

También siento lo mismo que @andyferris que el if entre la expresión y la iteración parece "transformar" el valor de la expresión en lugar de la forma de la iteración, y debería producir nogthing cuando la condición no se cumple (pero es posible que las comprensiones de python/haskell me echen a perder).

Obviamente x if false se evaluaría como nothing cuando no esté en el contexto de una expresión generadora. Sería perfectamente razonable admitir [x^2 if x % 3 == 0 for x=1:100] pero no x if y por sí mismo.

Personalmente, preferiría poder omitir end si solo hay una declaración.

if length(A) != length(B) throw(ArgumentError("..."))

Si no hay end , entonces podría suponer que solo había una expresión. ¿Supongo que eso se ha discutido extensamente antes?
Observo que preferiría no tener un punto y coma después de la condición - después de la expresión... _tal vez_... aunque no me gustaría.

Preferiría eso, que tener dos sintaxis diferentes para una forma similar de declaración if;if x; ...; end y if x then; ... . _(Editar: if condition then action ha crecido en mí.)_

Sería perfectamente razonable apoyar [x^2 si x % 3 == 0 para x=1:100] pero no x si y por sí mismo.

@StefanKarpinski Estoy totalmente de acuerdo con esto. Sin embargo...

Si la cláusula if está a la izquierda, los datos "fluyen" desde el extremo derecho al extremo izquierdo y al centro.

Leo x^2 if x % 2 == 0 for x in 1:10 como, x^2 where x % 2 == 0 for each x in 1:10 , que, dado que es comprensible, tiene sentido para mí; usted está más interesado en la transformación.
En consultas SQL, el mismo punto es cierto, ¿no?

Por lo tanto, no creo que tener el "generador" como punto de partida para leerlo sea del todo correcto, _para una comprensión_. Un bucle for por otro lado... Eso tiene más sentido.

Personalmente, prefiero poder omitir end si solo hay una declaración.

Propuse esto hace mucho tiempo, pero no tuvo ningún éxito: https://github.com/JuliaLang/julia/issues/1657. En realidad, este sería un cambio relativamente no disruptivo, ya que sería extraño y raro ver un código de escritura como este:

if cond body
end

¿Qué opinas sobre usar bloques do en lugar de then ? es decir: if x do y end

Solo un pequeño comentario adicional: no veo ninguna forma de que if x y por sí solo (es decir, fuera de un generador) pueda manejarse correctamente dentro de un editor sin un analizador julia en toda regla, ya que debe ser capaz de determinar cuántos tokens siguen al if . Estoy pensando en vim, pero supongo que otros editores pueden estar en la misma situación. Lo mismo podría ser cierto sobre y if x , pero no estoy seguro (divulgación completa: tampoco me gusta y if x por sí mismo; no estoy en contra if x y en principio, pero creo que puede ser un poco difícil de analizar también para los humanos, no solo para los editores).

@diegozea El mismo problema, creo. Todavía preferiría if x y .

@carlobaldassi Hay algunas cosas que podrías hacer para que sea más fácil de analizar para los humanos.

Podría forzar que ifs de una sola declaración no tuviera una nueva línea entre la condición y la expresión.
Sin embargo, no estoy seguro de que me gustaría que me obligaran a hacer eso con expresiones largas.

Alternativamente, puede forzar que haya una nueva línea después de la expresión si hubiera una nueva línea después de la condición; por lo tanto, lo siguiente no compilaría, pero daría un claro mensaje de error, por supuesto:

if length(A) != length(B)
    throw(ArgumentError("lengths must match")
if some_condition(A, B)
   N *= 2

Pero, esto sería:

if length(A) != length(B) throw(ArgumentError("lengths must match")
if some_condition(A, B) N *= 2

y esto sería:

if length(A) != length(B)
    throw(ArgumentError("lengths must match")

if some_condition(A, B)
   N *= 2

Esto también evitaría que cometiera este tipo de errores:

if is_present(x)
    y = 2 * x[]

    return y * 2

Creo que el mayor argumento a favor de if x then y que todavía gana a cualquier otra sintaxis es la legibilidad . Que if x y end , if x y o x && y sean más cortos es irrelevante en mi libro (más allá del hecho de que estamos hablando de una diferencia trivial de 1 a 5 caracteres) porque ninguno de esos son casi tan claros como if x then y . También evita que el editor analice problemas o que se rompa el código anterior. Es solo una sintaxis agradable, limpia y corta para declaraciones cortas if.

Sin embargo, reconozco la posible confusión del uso de if-then en el caso del generador; dado eso, estoy de acuerdo en que

x^2 if x % 3 == 0 for x = 1:100      # filtered generator
[ x^2 if x % 3 == 0 for x = 1:100 ]  # filtered comprehension

es más claro, reconociendo que la estructura de la expresión es

generated_value_expr  value_generator_expr  =>  generator_expression

[generator_filter_expr]  for_generator_expr  => value_generator_expr

es decir generator_filter_expr se aplica directamente a los valores generados a partir de for_generator_expr antes de pasar los valores no filtrados a generated_value_expr .

Creo que la distinción es importante aquí, porque no es la misma lógica que permitiría

println("positive") if x > 0 

TL;DR: Deberíamos tener x^2 if x % 3 == 0 for x = 1:100 para generadores filtrados, pero la misma lógica de sintaxis no se aplica a println("hey") if x > 0 , por lo tanto, aún deberíamos considerar if x then y para formato corto si-sintaxis. Aunque obviamente las dos ideas aquí ahora no tienen ninguna relación.

@ H-225 Eso me parece extraño y, en última instancia, no es de Julian, especialmente con la acción en una nueva línea sin end .

Todavía sería una pesadilla para un editor analizar porque a los editores (como Vim) no les importa qué es y qué no es una condición o acción; de hecho, no tienen forma de saberlo sin un analizador de Julia, sino que preocuparse por la ubicación de cosas como if y end . Creo que sería excepcionalmente difícil lograr que Vim reconozca que end no es necesario en ese escenario. Me doy cuenta de que hacerlo fácil para los editores no es un buen argumento para una decisión de diseño, solo digo.

Definitivamente :-1: por if x y de mi parte. Preferiría if x then y a eso, ya que es más fácil de analizar para mi pequeño cerebro. :stuck_out_tongue_winking_eye:

¿Hay alguna razón para no usar simplemente el operador de signo de interrogación ternario para la declaración if también? Ya puede imitar una declaración if haciendo

condition ? if_condition_true_eval_expr : nothing

¿por qué no hacerlo de modo que si no incluye dos puntos, entonces es una declaración if, entonces simplemente tendría

condition ? if_condition_true_eval_expr

de esta manera no tienes que introducir ninguna palabra clave nueva, ¿funcionaría?

@esproff Curiosamente, iba a sugerir lo contrario: extender la idea si-entonces en este julepe a una expresión de una sola línea si-entonces-otro

if cond then a else b

donde la cláusula else es opcional. Incluso podría bajar de manera idéntica a cond ? b : c . Para mí, se trata de alejarse del ternario de estilo C y avanzar hacia un código más legible por humanos. (Definitivamente he usado condition ? a : nothing antes; parece un truco (porque lo era, el nothing era importante por alguna extraña razón) y es confuso para que otras personas lo lean).

Pero claro, ¿por qué no podemos tener todas estas ideas simultáneamente?

@andyferris Sí, ese es el otro camino a seguir, Pythonic. Supongo que depende de lo conciso que quieras ser, los matemáticos generalmente parecen apreciar la concisión, pero, sinceramente, estaría feliz con cualquiera de los dos, siempre que no tenga que usar el torpe

if condition; eval_expr; end

pero, sinceramente, estaría contento con cualquiera de los dos, siempre que no tenga que usar el torpe

if condition; eval_expr; end

¡Por supuesto!

Por lo que vale, me gusta la notación x && y y no la veo como un abuso.

Personalmente, prefiero una solución basada en operadores que no devuelva false si la primera declaración es falsa. Estaría bien con casi cualquier cosa, aunque me gusta a ?: b como la versión de dos argumentos del operador ternario.

La idea ? se discutió bastante extensamente en #6823, podría valer la pena volver a leer esa discusión.

Llegué aquí de esa discusión, pero pensé que este era un mejor lugar para comentar. Creo que if a then b y usar solo ? sin : sería algo confuso, pero no me quejaría siempre que proporcionen la misma funcionalidad.

Estoy de acuerdo con @EricForgy. Tal vez solo estoy acostumbrado a ellos en este punto, pero para mí, usar && y || de esta manera se siente idiomático para Julia, particularmente para la verificación de errores (por ejemplo x || throw(y) ). No parecen tan ambiguos o ilegibles en absoluto. Además, realmente no veo por qué importaría que x && y devuelva false si x es falso porque probablemente no debería usarse al final de una función de todos modos , donde afectaría el valor de retorno de la función.

Los ternarios de estilo C son bastante omnipresentes; Yo diría que no son solo los matemáticos los que valoran esta sintaxis. El único lenguaje en el que puedo pensar que tiene ternarios pero que no es compatible con el estilo C es Python, y FWIW desprecio los ternarios de Python. condition ? action1 : action2 es compacto y legible siempre que use espacios en blanco y respete la longitud de las líneas. Para condiciones y acciones más largas, se debe usar

if condition
    somelongaction1
else
    somelongaction2
end

de todos modos para la legibilidad.

Con respecto a then , el punto de esta discusión, FWIW, probablemente no lo usaría incluso si se implementara porque, nuevamente, && y || me parecen idiomáticos. Aunque tomaría then en un santiamén por if x y , x ? y o x ? y : nothing .

Personalmente, prefiero y if x . Puede parecer al revés, pero hay una precedencia más allá de Ruby y Perl: la sintaxis de casos matemáticos es así.

image

No _me gusta_ usar && o || para esto, ya que nunca recuerdo que x && y = z no se analiza de la manera que esperaba. Creo que tiene una carga cognitiva mayor que y if x ; eso va por if x y también.

En mi opinión, x ? y _huele_ como un error de sintaxis, independientemente de si es realmente válido.

x ?? y quizás? x ?: y es una extensión GNU C que significa x ? x : y , por lo que ?? y ?: podrían ser versiones de baja prioridad de && y || , tal vez.

Mi orden de preferencia: y if x == x ?? y < if x then y < x && y < x ? y < if x y .

FWIW. Prefiero la concisión y la separación clara del código con ? , && y || , aunque la sintaxis cond ? expr podría ser más clara que la de && .

Me gusta hacer con frecuencia el tipo de flujo goodcondition || return , lo cual no es fácil con las declaraciones if. No me gustaría perder eso (o que me intimiden para que no lo use)

Para el ternario sin : , podría ser bueno permitir bloques concisos if / elseif sin una condición else :

x==5 ? f1() :
x==6 ? f2()

y uno podría imaginar extender esto a declaraciones de tipo interruptor:

match x:
    5 ? f1() :
    6 ? f2()

En términos de legibilidad, depende. Para muchas condiciones/acciones cortas es mucho más legible (¡con espacios limpios!) poder alinear condiciones/acciones en líneas sucesivas con separadores claros.

Para los generadores, preferiría where o when en lugar de reutilizar if , ya que es un filtro, no un condicional:

x = [i^2 for i in 1:10 when i%2 == 0]

Creo que está más claro que esto significa x = [i^2 for i in filter(..., 1:10)] .

Notaré que desde que discutí esto, ya no me opondría a if condition then action , ya me ha crecido.
Julia tiende a apoyarse en el lado más "prolijo", con function y end , etc., así que creo que encajaría perfectamente. También es un poco irritante tener que agregar corchetes alrededor expresiones si va y viene entre la sintaxis condition && action .

Con respecto a la sintaxis de Perl/Ruby "acción si condición": me gusta mucho esta sintaxis, y aunque estoy de acuerdo en que puede reducir la legibilidad cuando se usa incorrectamente, también creo que a veces _aumenta_ la legibilidad.

Por ejemplo:

throw(DomainError()) if some_condition || some_other_condition && so_on

Después de leer "lanzar error de dominio si" ya sabe que lo que sigue será una verificación de cordura en la entrada. Luego puede saltar a la siguiente línea si los detalles del condicional no son importantes para usted.

La oración anterior es un ejemplo de cómo esta construcción ocurre con frecuencia en el lenguaje natural. La acción "pasar a la siguiente línea" viene primero, y la menos importante "si no estás interesado" viene en una oración subordinada. Una vez más, el lector podría adivinar aproximadamente lo que seguirá a la palabra "si" sin tener que leer hasta el final de la oración.

(También daré una oración de ejemplo autorreferencial, si puedo pensar en una).

Como experto en Perl, simpatizo con esta sintaxis, pero creo que va a ser difícil venderla a otros que no tengan antecedentes en Perl. Un argumento a favor es que coincide con la sintaxis del filtro en las comprensiones. Un argumento en contra es que es extraño tener una construcción donde el orden de evaluación no es de izquierda a derecha. Por supuesto, las comprensiones tienen precisamente eso, así que 🤷‍♂️

Para mí, una pregunta relacionada es entonces: ¿estamos generalizando la ramificación o el filtrado? Esta es una generalización de la semántica (y sintaxis) de ramificación if , por lo que tal vez sería desafortunado tomar prestada la sintaxis de comprensiones / generadores para este propósito donde esa sintaxis ya indica filtrado.

(Por cierto, me encantaría una buena sintaxis para filtrar, como nuestra buena sintaxis . . Para ilustrar mi punto anterior, tal vez un map - filter podría verse como f.(a) if g.(a)

f(x) for x in a # lazy map
f(x) for x in a if g(x) # lazy map - filter
x for x in a if g(x) # lazy filter where `f` is `identity`

f.(a) # map / broadcast
f.(a) if g.(a) # like a map/broadcast - filter operation
a if g.(a) # like the above where `f` is implicitly `identity`
[1,2,3] if [true, false, true] == [1, 3] # or something... here we simply make `if` an infix operator for filtering

Perdón por salirme del tema y no estoy seguro de que lo anterior sea una buena idea, pero solo señalo que podría haber otro uso potencial de la sintaxis if filtrado por comprensión que tiene semántica de filtrado)

Finalmente, estoy de acuerdo con las observaciones anteriores de @tbreloff ... el binario ? es la sintaxis más compacta (y el objetivo de este hilo es hacer una sintaxis compacta), y siempre encontré if una elección un tanto sorprendente para el filtrado de generadores.

@StefanKarpinski escribió:

La sintaxis del modificador if/for estilo Perl/Ruby parece que se combinaría mejor con esto. En otras palabras:
julia println("positive") if x > 0 # conditional execution x^2 for x=1:100 # generator [ x^2 for x=1:100 ] # comprehension x^2 if x % 3 == 0 for x = 1:100 # filtered generator [ x^2 if x % 3 == 0 for x = 1:100 ] # filtered comprehension
También tiene la ventaja de tener un precedente en otros idiomas, lo que no parece tener la sintaxis si-entonces sin fin.

Y también sería mejor para la gramática.

Creo que [x^2 if x % 3 == 0 for x = 1:100] debería ser:

[(x^2 if x % 3 == 0) for x = 1:100]
 ```
Then `for` stay's in infix position which is currently an error. Of course we can change its meaning because of leading `[` but it would not work as generator:
```julia
x^2 if x % 3 == 0 for x = 1:100

Creo que [x^2 if x % 3 == 0 for x = 1:100] debería ser:

Eso no sería un generador filtrado. 2 if x devuelve 2 cuando x es verdadero, pero también tiene que devolver algo cuando x es falso; normalmente sería nothing . Entonces eso daría una serie de números y nada. Eso es en parte por qué if tiene que ir después for en la sintaxis del generador filtrado.

Sí, tiene usted razón. Tal vez debería escribirse así:

[for x = 1:100 x^2 if x % 3 == 0]

Afaics, esto sería analizable válido sin el uso de paréntesis, ¡genial!

Sólo de pensar...

[ for x = 1:100 if x % 3 == 0 push x^2]
for x = 1:100 if x % 3 == 0 push x^2  # other keyword could be used, e.g. yield

Esto es más similar a la construcción natural.

for x=1:100 
    if x%3==0 
          push!(somearray, x^2)
    end
end

Acabo de ver este julepe de nuevo mientras miraba otra cosa.

Todavía deseo algo como el formulario de una sola línea if a then b ; Encuentro que el reemplazo juliano a && b es bastante ilegible incluso después de usarlo durante varios años: simplemente no hay forma de leerlo directamente como una oración en inglés.

También siento que la necesidad de explicar el modismo a && b a los recién llegados es un poco vergonzoso cuando podríamos tener una sintaxis alternativa que es evidente y solo un poco más larga.

simplemente no hay forma de leerlo directamente como una oración en inglés

a && b se lee como "a y b" como en "si a entonces también haz b"
a || b se lee como "a o b" como en "a debe ser cierto, de lo contrario haz b"

Sé lo que hace y lo uso de vez en cuando por brevedad. Pero por mucho que lo intente (como se mencionó, desde hace varios años) no puedo ver "a y b" como una oración. Es solo una leve disonancia cognitiva cada vez.

Por el contrario, siempre he encontrado que "a o b" son bastante legibles.

Curiosamente, diferentes aspectos de esto surgieron dos veces hoy en el trabajo.

Por la mañana, tuvimos un PR de Julia que usaba && en lugar de if ... end y señalé que, como lector de códigos (revisor de relaciones públicas), requería un esfuerzo adicional (y era fácil pasarlo por alto) ) ramas que pueden o no ejecutarse. El ejemplo era de la forma a() && b!() donde b! es extremadamente mutante. (En este caso, b!() movió o eliminó archivos en el sistema de archivos, lo que parecía inmediatamente peligroso, pero mi cerebro no podía darse cuenta de que esto solo era problemático cuando !a() y que este caso en realidad se protegió correctamente).

Por la tarde, otro ingeniero de software (que no conoce a Julia) señaló que, al hablar inglés con amigos, a veces respondía la pregunta de la forma "¿Es a o b con la respuesta "sí". Sólo sus amigos ingenieros de software lo entenderían; todos los demás no lo entenderían en absoluto . La gente normal simplemente no piensa de esa manera. 🙂 Esto se relaciona un poco con mi siguiente punto (EDITAR: y debería haber dicho, se relaciona con la respuesta de Stefan anterior, que para muchas personas no creo que se les ocurra).

Mi postura sobre este tema todo el tiempo es que usar && (o || ) es una sintaxis corta para la bifurcación que solo pueden leer las personas con una sólida experiencia en PL, e incluso entonces agrega un poco de carga cognitiva/visual (simplemente para distinguir & vs && ). Siento que cuando se trabaja en equipos multidisciplinarios (mezcla de científicos e ingenieros de software) se confunde activamente a la mitad del equipo. Incluso como ingeniero de software, siento que tenemos una extraña desconexión entre el &(::Bool, ::Bool) --> Bool lógico y el &&(::Bool, ::Any) --> Any ramificado (sí, este último no es realmente una función, pero espero que entiendas mi punto) . Además de los tipos en sí, en Julia normalmente espero que los primeros sean "funcionales", mientras que la última forma a menudo implica posibles efectos secundarios, especialmente en la segunda expresión.

EDITAR: pensando más en esto, el problema aquí es completamente sobre los efectos secundarios y el flujo del programa. Es bastante fácil para todos entender que el uso "funcional" de && es una optimización de & . Es relativamente difícil conciliar que son completamente diferentes para expresiones no puras.

En algunos casos, creo que la "precedencia" es más clara con if a then b :

guard && c += 1    # probably an error because it's parsed as (guard && c) += 1
guard && (c += 1)  # parentheses required 

if guard then c += 1  # no ambiguity here

Además, el resaltado de sintaxis en los editores ayudaría a marcar if al comienzo de la expresión.

También tiene la ventaja de tener un precedente en otros idiomas, que la sintaxis if - then sin end no parece tener.

Cabe señalar que _hay muchos_ precedentes para la sintaxis if-then-else :

Y esa sintaxis se puede usar para frases ingeniosas en todos los idiomas anteriores.

He estado al tanto de esta discusión durante toda una hora, así que discúlpeme si se ha sugerido esto.

Me parece que las opciones de cortocircuito de '&&' y '||' se usan porque queremos declaraciones if simples en una línea, sin punto y coma. Pero el cortocircuito parece una solución que crea otro problema: como humam, es difícil comprender y analizar esa sintaxis sin haberla visto antes, o sabiendo que la segunda expresión solo se evalúa cuando es necesario. La lectura poco intuitiva (como ser humano) parece deberse a imperfecciones tanto visuales como lógicas con cortocircuitos. Incluso parece que después de saber lo que significa, puede ser más difícil de lo que debería ser de leer.

Si no me equivoco, ambos problemas podrían solucionarse con una macro:

resultado de la condición @if

La negación se puede manejar con un ! antes de la condición, o alternativamente una macro @ifnot . ¿Soy solo yo, o está libre de ambigüedad para la computadora, fácil de leer para el humano y todo en una sola línea?

Incluso parece que después de saber lo que significa, puede ser más difícil de lo que debería ser de leer.

^ Estoy totalmente de acuerdo con esto.

resultado de la condición @if

Ya puede hacer lo siguiente, que se ve casi igual:

if condition result end

A continuación se muestra una macro para la sintaxis completa if-then-else. Sin embargo, dado que if y else son palabras clave reservadas, la macro usa If , Then y Else en su lugar.

syntax_error() = error("Valid syntax is either `<strong i="20">@If</strong> cond Then ex` or `<strong i="21">@If</strong> cond Then ex1 Else ex2`")

function If(exprs...)
    n_args = length(exprs)

    if n_args == 3
        if exprs[2] != :Then
            syntax_error()
        end

        ex = quote
            if $(exprs[1])
                $(exprs[3])
            end
        end
    elseif n_args == 5
        if ( exprs[2] != :Then ) || ( exprs[4] != :Else )
            syntax_error()
        end

        ex = quote
            if $(exprs[1])
                $(exprs[3])
            else
                $(exprs[5])
            end
        end
    else
        syntax_error()
    end

    return esc(ex)
end

macro If(exprs...)
    If(exprs...)
end

foo(x) = <strong i="22">@If</strong> x > 0 Then println("greater than zero") Else println("less than zero")

Y aquí podemos ver foo en acción:

julia> foo(3)
greater than zero

julia> foo(-3)
less than zero

preferiría algo como

x0 = 1
x1 = 2
x3 = 3 when y>0  # y>0 is evaluated first
x4 = 4

when tendría menos precedencia que = y operaba de derecha a izquierda.

Ya puede hacer lo siguiente, que se ve casi igual:

if condition result end

¡No sabía eso! Siempre pensé que necesitaba los puntos y comas donde normalmente hay una nueva línea. Así que en mi caso, la sintaxis

if condition result end

hace completamente redundante el uso de && , ¡así que no hay problema! Veo que uno puede incluso hacer lo siguiente:

if condition result_1 else result_2 end

En este caso, agregar la palabra clave end probablemente sea más fácil que hacer una macro. Pero gracias por tomarse el tiempo para hacerlo de todos modos ^_^ ¿Es una buena idea agregar la posibilidad de declaraciones if de una línea en la documentación? Veo que si uno hace ?If<enter> el resultado ya son bastantes líneas... Pero siento que esta función debería publicitarse más.

Con respecto a la discusión original, estoy a favor de agregar "Si x, entonces y", aunque lo encuentro un poco redundante con la versión de una línea de "si". Pero oye, escribe el código como tenga sentido para ti, ¿verdad?

¿Fue útil esta página
0 / 5 - 0 calificaciones

Temas relacionados

i-apellaniz picture i-apellaniz  ·  3Comentarios

Keno picture Keno  ·  3Comentarios

StefanKarpinski picture StefanKarpinski  ·  3Comentarios

ararslan picture ararslan  ·  3Comentarios

omus picture omus  ·  3Comentarios