Julia: mini julep : si x alors y

Créé le 16 mai 2016  ·  53Commentaires  ·  Source: JuliaLang/julia

Dans diverses discussions, il a été suggéré d'autoriser une syntaxe telle que :

if x then y

En tant qu'instruction "si" abrégée et alternative à l'instruction commune :

x && y

syntaxe qui exploite l'opérateur de court-circuit && pour exécuter conditionnellement y (avec y contenant souvent d'autres effets secondaires et ne renvoyant pas nécessairement un Bool ).

Les principaux avantages de cette construction if-then étant : un code plus lisible, s'appuyant moins sur l'abus && et incluant formellement une forme d'instruction "if" qui ne nécessite pas de end mot-clé.

Il m'est venu à l'esprit l'autre jour que cette syntaxe fournirait également un moyen pratique pour implémenter #550, qui ressemblerait à :

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

S'appuyant sur le fait que if-then ne nécessite pas de mot-clé end , dont nous aurions probablement besoin sous une forme ou une autre, même si nous utilisions des gardes de style python :

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

Pour être clair, la syntaxe de Julia guard ferait essentiellement une réécriture à partir de :

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

à

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

Aussi, à titre de clarification, cela permettrait la syntaxe de garde au niveau _generator_ par opposition au niveau _comprehension_ (qui correspond également à ce que python permet également).

julep

Commentaire le plus utile

Peut-être que je suis minoritaire puisque d'autres langages ont adopté cette approche, mais j'ai toujours trouvé l'action précédant la condition vraiment bizarre, par exemple println("positive") if x > 0 . Je suppose que c'est plus concis que if x > 0 println("positive") end mais au moins pour moi, cela se fait au détriment de la lisibilité.

J'y pense comme une conversation :

Julia : "Je vais imprimer une ficelle..."
Harold : "Génial !"
Julia : "...mais seulement si certaines conditions sont remplies."
Harold : "Oh. :("

contre

Julia : "Si une condition est remplie, j'imprimerai une chaîne."
Harold : "D'accord, cool."

Tous les 53 commentaires

La syntaxe du modificateur if/for de style Perl/Ruby semble mieux se mélanger avec cela. En d'autres termes:

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

Il a également l'avantage d'avoir un précédent dans d'autres langages, ce que la syntaxe if - then sans end ne semble pas avoir.

Juste une remarque sur la gestion des problèmes : # 6823 a traité exactement de ce problème. À un moment donné, il a été fermé sans commentaire, j'ai demandé pourquoi il était fermé car il n'y avait clairement pas eu de consensus pour le fermer, mais je n'ai jamais reçu de réponse. Il semble qu'il serait plus efficace de ne pas fermer les problèmes comme # 6823, sinon ces discussions tourneront en rond et tous les points du problème d'origine seront répétés à nouveau. Il aurait probablement été logique de changer le titre de # 6823 à un moment donné, puis de l'ajouter ici.

Oui, bon point. En effet #6823 semble être à mi-parcours et n'aurait probablement pas dû être fermé.

Peut-être que je suis minoritaire puisque d'autres langages ont adopté cette approche, mais j'ai toujours trouvé l'action précédant la condition vraiment bizarre, par exemple println("positive") if x > 0 . Je suppose que c'est plus concis que if x > 0 println("positive") end mais au moins pour moi, cela se fait au détriment de la lisibilité.

J'y pense comme une conversation :

Julia : "Je vais imprimer une ficelle..."
Harold : "Génial !"
Julia : "...mais seulement si certaines conditions sont remplies."
Harold : "Oh. :("

contre

Julia : "Si une condition est remplie, j'imprimerai une chaîne."
Harold : "D'accord, cool."

@ararslan : Je ne suis pas en désaccord, ce qui est l'une des raisons pour lesquelles cette fonctionnalité n'est pas dans Julia malgré l'art antérieur de Ruby et Perl. Cependant, il se mélange beaucoup mieux avec la syntaxe du modificateur for pour les générateurs et les compréhensions, c'est pourquoi je l'ai évoqué ici.

@StefanKarpinski Ouais d'accord, ça s'accorde mieux avec ceux-là. Je suis toujours désespérément attaché aux conditions qui précèdent les actions. :sourire: (Mais comme je me suis souvent mis à le dire récemment, mon opinion n'a pas vraiment d'importance ; je ne suis qu'un mec.)

Je suppose que si vous aviez quelque chose comme

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

alors il n'est pas immédiatement clair que vous démarrez une compréhension/générateur/machin, car il se lit également comme s'il pouvait être regroupé comme

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

c'est-à-dire, si une condition alors générateur. ça ne me dérangerait pas

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... ¯\_(ツ)_/¯

Je suppose que si la condition devait suivre l'action dans un générateur, je pense que je préférerais un mot-clé différent de if , par exemple where . Ensuite, il se lit presque comme une requête SQL, par exemple

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

Je pense que where rend un peu plus clair que vous filtrez les valeurs de x produites par le for que ne le fait if .

Il me semble plus agréable d'avoir le flux de données dans une seule direction, bien que dans ce cas de droite à gauche plutôt que de gauche à droite.

Pouvez-vous préciser ce que vous entendez par là ?

Le for 1:n "génère" des valeurs, le if x % 3 == 0 les filtre et le x^2 les transforme - les générateurs circulent déjà de droite à gauche et pour maintenir ce flux, le filtre doit aller dans le milieu. Si la clause if va à droite de la clause for alors les données "fluent" du milieu vers l'extrême droite puis vers l'extrême gauche, ce qui est bizarre. Si la clause if se trouve à gauche, les données « circulent » de l'extrême droite vers l'extrême gauche vers le milieu. Je sais que SQL place la clause where à droite des noms de table et les expressions à gauche - parce que cela se lit plus comme l'anglais - mais j'ai toujours trouvé cela ennuyeux à lire et je pense que lire comme l'anglais n'est pas une heuristique qu'il faut pousser trop loin dans la conception d'un langage de programmation.

Choses que je n'aime pas à propos if x then y :

  1. Il introduit le nouveau mot-clé then .
  2. C'est plus court d'écrire if x y end que if x then y ; x && y est encore plus court.
  3. Le mot-clé then est largement utilisé dans les langages pour le type de syntaxe exactement opposé : une syntaxe multiligne if qui nécessite un mot-clé end (ou fi en bash , beurk).

Oh oui, je vois ce que tu veux dire maintenant à propos du flux. Ça a du sens. Merci pour l'explication!

Serait-ce bizarre de pouvoir faire

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

et _ne pas_ pouvoir faire

println("positive") if x > 0

?

Tous les bons points.

En fait, j'aime beaucoup la syntaxe proposée par @StefanKarpinski dans son premier commentaire. Je suis principalement intéressé par les générateurs conditionnels, avec une forme courte _if_ plus générale en bonus.

En ce qui concerne les générateurs, je lisais le if (ou where - je n'ai pas d'opinion à ce sujet) pour faire partie de la gamme... il crée un itérateur x = 1:10 if/where x % 2 == 0 , qui est ensuite combiné avec l'expression à gauche pour créer un tableau (ou générateur).

Dans un sens, x = 1:10 where x % 2 == 0 est lui-même un générateur pour une sorte d'itérable. Cela pourrait être une syntaxe autonome, non ?

Je pense que le filtrage est en quelque sorte une opération différente de l'instruction conditionnelle if a then b . Le filtrage agit sur la plage d'itération. Lorsque le if a then b est combiné avec l'expression à gauche du générateur, je m'attendrais à ce qu'il émette nothing dans les cas où a était false . Comparez ce qui se passe logiquement si j'ajoute des parenthèses :

[(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]

Prenant les exemples de @ararslan , si nous permettons

println("positive") if x > 0

alors à mon humble avis, il s'ensuit que

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

devrait probablement émettre nothing, nothing, 9, nothing, nothing, 36, ...

Enfin, si nous devions adopter une sténographie conditionnelle if , mon vote est pour la condition avant la déclaration, pour les raisons décrites par le premier message de @ararslan - étant la principale de moindre surprise à la lecture du code. (rappelez-vous, s'ils disent que le code est plus lu qu'écrit, alors if a then b est une meilleure syntaxe a && b même si cette dernière est plus courte). Cela signifie également que les deux types possibles de if à l'intérieur du générateur seraient distincts - à l'extrême gauche - avec l'expression - ou à l'extrême droite - avec la plage.

Quant à la tradition en Ruby/Perl, je pense qu'il est préférable d'essayer de trouver la meilleure solution plutôt que de s'enliser dans la tradition. Si cela fonctionne et semble naturel, les gens l'aimeront.

De plus, si nous avons if/where dans les plages, devons-nous veiller à ce que la plage reste cartésienne pour les générateurs multidimensionnels ?

# 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]

C'est plutôt cool et plutôt horrible !

Je pense que le filtrage est en quelque sorte une opération différente de l'instruction conditionnelle if a then b.

Oui! J'étais sur le point de poster ce même commentaire. Le filtrage opère sur l'itérateur dans son ensemble et ne fait pas partie de l'expression calculée à l'intérieur.

Je ressens également la même chose que @andyferris que le if entre l'expression et l'itération semble "transformer" la valeur de l'expression plutôt que la forme de l'itération, et devrait produire nogthing quand la condition n'est pas remplie (mais je peux être gâté par les compréhensions python/haskell).

De toute évidence, x if false serait évalué à nothing lorsqu'il n'est pas dans le contexte d'une expression de générateur. Il serait parfaitement raisonnable de prendre en charge [x^2 if x % 3 == 0 for x=1:100] mais pas x if y par lui-même.

Personnellement, je préférerais pouvoir omettre end s'il n'y a qu'une seule instruction.

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

S'il n'y a pas end , alors il pourrait supposer qu'il n'y avait qu'une seule expression. Je suppose que cela a déjà été longuement discuté?
Je note que je préférerais ne pas avoir de point-virgule après la condition - après l'expression... _peut-être_... Je n'aimerais pas ça cependant.

Je préférerais de loin cela plutôt que d'avoir deux syntaxes différentes pour une forme similaire d'instruction if ;if x; ...; end et if x then; ... . _(Modifier : if condition then action a grandi sur moi.)_

Il serait parfaitement raisonnable de prendre en charge [x^2 si x % 3 == 0 pour x=1:100] mais pas x si y par lui-même.

@StefanKarpinski Je suis totalement d'accord avec cela. Pourtant...

Si la clause if est à gauche, les données « circulent » de l'extrême droite vers l'extrême gauche vers le milieu.

J'ai lu x^2 if x % 2 == 0 for x in 1:10 comme, x^2 where x % 2 == 0 for each x in 1:10 , ce qui, puisque c'est de la compréhension, a du sens pour moi ; vous êtes le plus intéressé par la transformation.
Dans les requêtes SQL, le même point est vrai, non ?

Je ne pense donc pas qu'avoir le "générateur" comme point de départ pour le lire, soit tout à fait juste, _pour une compréhension_. Une boucle for par contre... Cela a plus de sens.

Personnellement, je préférerais pouvoir omettre end s'il n'y a qu'une seule déclaration.

Je l'ai proposé il y a longtemps mais cela n'a pas eu de succès : https://github.com/JuliaLang/julia/issues/1657. Ce serait en fait un changement relativement non perturbateur car il serait étrange et rare de voir du code écrit comme celui-ci :

if cond body
end

Que pensez-vous de l'utilisation de blocs do au lieu d'un then ? c'est-à-dire : if x do y end

Juste un petit commentaire secondaire: je ne vois aucun moyen pour que if x y par lui-même (c'est-à-dire en dehors d'un générateur) puisse être géré correctement dans un éditeur sans un analyseur julia complet, car vous devez être capable de déterminer combien de jetons suivent le if . Je pense à vim, mais je suppose que d'autres éditeurs peuvent être dans la même situation. La même chose pourrait être vraie à propos y if x , mais je ne suis pas sûr (divulgation complète : je n'aime pas non plus vraiment y if x en soi ; je ne suis pas contre if x y en principe mais pense qu'il peut être légèrement difficile à analyser pour les humains également, pas seulement pour les éditeurs).

@diegozea Même problème, je pense. Je préférerais toujours if x y .

@carlobaldassi Il y a certaines choses que vous pourriez faire pour faciliter l'analyse par les humains.

Vous pouvez forcer cette instruction unique à ne pas avoir de retour à la ligne entre la condition et l'expression.
Je ne suis pas sûr que j'aimerais être obligé de le faire pour de longues expressions, cependant.

Alternativement, vous pouvez forcer qu'il y ait un retour à la ligne après l'expression s'il y avait un retour à la ligne après la condition ; ainsi, ce qui suit ne compilerait pas, mais donnerait bien sûr un message d'erreur clair :

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

Mais cela donnerait :

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

et cela donnerait :

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

if some_condition(A, B)
   N *= 2

Cela vous éviterait aussi de faire ce genre d'erreurs :

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

    return y * 2

Je pense que le plus gros argument pour if x then y qui l'emporte toujours sur toute autre syntaxe est la lisibilité . Que if x y end , if x y ou x && y soient plus courts n'est pas pertinent dans mon livre (au-delà du fait que nous parlons d'une différence triviale de 1 à 5 caractères) car aucun de ces sont presque aussi clairs que if x then y . Cela évite également à l'éditeur les problèmes d'analyse ou la rupture possible du code antérieur. C'est juste une syntaxe agréable, propre et courte pour les instructions courtes si.

Je reconnais cependant la confusion potentielle de l'utilisation de if-then dans le cas du générateur ; étant donné que, je suis d'accord 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

est la plus claire, reconnaissant que la structure de l'expression est

generated_value_expr  value_generator_expr  =>  generator_expression

[generator_filter_expr]  for_generator_expr  => value_generator_expr

c'est-à-dire que le generator_filter_expr est appliqué directement aux valeurs générées à partir de for_generator_expr avant de passer les valeurs non filtrées au generated_value_expr .

Je pense que la distinction est importante ici, car ce n'est pas la même logique qui permettrait

println("positive") if x > 0 

TL; DR : Nous devrions avoir x^2 if x % 3 == 0 for x = 1:100 pour les générateurs filtrés, mais la même logique de syntaxe ne s'applique pas à println("hey") if x > 0 , par conséquent, nous devrions toujours considérer if x then y pour la forme courte si-syntaxe. Bien qu'évidemment les deux idées ici soient maintenant complètement indépendantes.

@ H-225 Cela me semble bizarre et finalement non julien, en particulier avec l'action sur une nouvelle ligne sans end .

Ce serait toujours un cauchemar pour un éditeur d'analyser parce que les éditeurs (comme Vim) ne se soucient pas de ce qui est et n'est pas une condition ou une action - en effet, ils n'ont aucun moyen de savoir sans un analyseur Julia - mais plutôt ils faites attention au placement de choses comme if et end . Je pense qu'il serait exceptionnellement difficile de faire en sorte que Vim reconnaisse que end n'est pas nécessaire dans ce scénario. Je me rends compte que faciliter les choses pour les éditeurs n'est pas un bon argument pour une décision de conception, je dis juste.

Certainement :-1 : pour if x y de ma part. Je préférerais if x then y à cela, car c'est plus facile à analyser pour mon petit cerveau. :tuck_out_tongue_winking_eye:

Existe-t-il une raison de ne pas simplement utiliser l'opérateur de point d'interrogation ternaire pour l'instruction if également ? Vous pouvez déjà imiter une instruction if en faisant

condition ? if_condition_true_eval_expr : nothing

pourquoi ne pas simplement faire en sorte que si vous n'incluez pas deux-points, alors c'est une instruction if, alors vous auriez juste

condition ? if_condition_true_eval_expr

de cette façon, vous n'avez pas à introduire de nouveaux mots clés, est-ce que cela fonctionnerait ?

@esproff Curieusement, j'allais suggérer le contraire: étendre l'idée si-alors dans ce julep à une seule ligne expression si-alors-sinon

if cond then a else b

où la clause else est facultative. Il pourrait même baisser de manière identique à cond ? b : c . Pour moi, il s'agit de s'éloigner du ternaire de style C et d'aller vers un code plus lisible par l'homme. (J'ai certainement utilisé condition ? a : nothing auparavant - cela ressemble à un hack (parce que c'était le cas, le nothing était important pour une raison obscure) et c'est déroutant pour les autres à lire).

Mais bien sûr, pourquoi ne pouvons-nous pas avoir toutes ces idées simultanément ?

@andyferris Oui, c'est l'autre, Pythonic, chemin à parcourir. Je suppose que cela dépend de la concision que vous voulez être, les mathématiciens semblent généralement apprécier le laconisme, mais honnêtement, je serais heureux avec l'un ou l'autre, tant que je n'ai pas à utiliser le maladroit

if condition; eval_expr; end

mais honnêtement, je serais heureux avec l'un ou l'autre, tant que je n'ai pas à utiliser le maladroit

if condition; eval_expr; end

En effet!

Pour ce que ça vaut, j'aime la notation x && y et je ne la vois pas comme un abus.

Personnellement, je préfère une solution basée sur un opérateur qui ne renvoie pas false si la première instruction est fausse. Je serais d'accord avec à peu près n'importe quoi, bien que j'aime a ?: b comme version à deux arguments de l'opérateur ternaire.

L'idée de ? été discutée assez longuement dans #6823, cela vaut peut-être la peine de relire cette discussion.

Je suis arrivé ici après cette discussion, mais j'ai pensé que c'était un meilleur endroit pour commenter. Je pense que if a then b et utiliser seulement ? sans : seraient quelque peu déroutants, mais ne se plaindraient pas tant qu'ils fournissent la même fonctionnalité.

Je suis d'accord avec @EricForgy. Peut-être que je suis juste habitué à eux à ce stade, mais pour moi, utiliser && et || de cette manière semble idiomatique pour Julia, en particulier pour la vérification des erreurs (par exemple x || throw(y) ). Ils ne semblent pas du tout ambigus ou illisibles. De plus, je ne vois pas vraiment pourquoi il serait important que x && y renvoie false si x est faux car il ne devrait probablement pas être utilisé à la fin d'une fonction de toute façon , où cela affecterait la valeur de retour de la fonction.

Les ternaires de style C sont assez omniprésents ; Je dirais que ce ne sont pas seulement les mathématiciens qui apprécient cette syntaxe. Le seul langage auquel je peux penser de manière désinvolte qui a des ternaires mais ne prend pas en charge le style C est Python, et FWIW je méprise les ternaires Python. condition ? action1 : action2 est à la fois compact et lisible tant que vous utilisez des espaces et respectez les longueurs de ligne. Pour des conditions et des actions plus longues, il faut utiliser

if condition
    somelongaction1
else
    somelongaction2
end

en tout cas pour la lisibilité.

En ce qui concerne then , le point de cette discussion, FWIW, je ne l'utiliserais probablement pas même s'il était implémenté car, encore une fois, && et || me semblent idiomatiques. Bien que je prendrais then en un clin d'œil sur if x y , x ? y ou x ? y : nothing .

Personnellement, je préfère largement y if x . Cela peut sembler être le mauvais chemin à suivre, mais il existe une priorité au-delà de Ruby et Perl : la syntaxe mathématique des cas est ainsi

image

Je n'aime pas utiliser && ou || pour cela, car je ne me souviens jamais que x && y = z n'analyse pas comme je m'y attendais. Je pense qu'il a une charge cognitive plus élevée que y if x ; cela vaut aussi pour if x y .

IMO, x ? y _smells_ comme une erreur de syntaxe, qu'elle soit ou non valide.

x ?? y peut-être ? x ?: y est une extension GNU C signifiant x ? x : y , donc ?? et ?: pourraient être des versions à faible priorité de && et || , peut-être.

Mon ordre de préférence : y if x == x ?? y < if x then y < x && y < x ? y < if x y .

FWIW. Je préfère la concision et la séparation claire du code avec ? , && et || , bien que la syntaxe cond ? expr puisse être plus claire que && .

J'aime faire fréquemment le type de flux goodcondition || return , ce qui n'est pas facile avec les instructions if. Je ne voudrais pas perdre ça (ou être intimidé pour ne pas l'utiliser)

Pour le ternaire sans : , il peut être intéressant d'autoriser des blocs laconique if / elseif sans condition else :

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

et on pourrait imaginer étendre ceci aux déclarations de type switch :

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

Pour la lisibilité, ça dépend. Pour de nombreuses conditions/actions courtes, il est beaucoup plus lisible (avec un espacement propre !!) de pouvoir aligner les conditions/actions sur des lignes successives avec des séparateurs clairs.

Pour les générateurs, je préférerais where ou when plutôt que de réutiliser if , car il s'agit d'un filtre et non d'une condition :

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

Je pense qu'il est plus clair que cela signifie x = [i^2 for i in filter(..., 1:10)] .

Je noterai que depuis que j'en ai discuté, je ne m'opposerais plus à if condition then action - c'est plutôt grandi sur moi.
Julia a tendance à se pencher du côté le plus "verbeux", avec function et end , etc., donc je pense que ça irait parfaitement. C'est aussi un peu irritant de devoir ajouter des parenthèses autour expressions si vous faites des allers-retours entre la syntaxe condition && action .

En ce qui concerne la syntaxe Perl/Ruby "action si condition": j'aime beaucoup cette syntaxe, et bien que je reconnaisse qu'elle peut réduire la lisibilité lorsqu'elle est utilisée de manière incorrecte, je pense aussi qu'elle _augmente_ parfois la lisibilité.

Par example:

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

Après avoir lu "lancer une erreur de domaine si", vous savez déjà que ce qui suit sera une vérification de l'intégrité de l'entrée. Vous pouvez ensuite passer à la ligne suivante si les détails du conditionnel ne sont pas importants pour vous.

La phrase précédente est un exemple de la façon dont cette construction se produit fréquemment en langage naturel. L'action "passer à la ligne suivante" vient en premier, et la moins importante "si vous n'êtes pas intéressé" vient dans une clause subordonnée. Encore une fois, le lecteur pourra peut-être deviner approximativement ce qui suivra le mot "si" sans réellement lire jusqu'à la fin de la phrase.

(Je donnerai également une phrase d'exemple autoréférentielle, si je peux en penser une.)

En tant qu'ancien de Perl, je suis sympathique à cette syntaxe mais je pense que ça va être difficile à vendre à d'autres qui ne viennent pas d'un milieu Perl. Un argument en faveur est qu'il correspond à la syntaxe du filtre dans les compréhensions. Un argument contre est qu'il est bizarre d'avoir une construction où l'ordre d'évaluation n'est pas de gauche à droite. Bien sûr, les compréhensions ont précisément cela, alors 🤷‍♂️

Pour moi, une question connexe est alors : généralisons-nous le branchement ou le filtrage ? Il s'agit d'une généralisation de la sémantique (et de la syntaxe) de branchement if , il serait donc peut-être regrettable d'emprunter la syntaxe des compréhensions / générateurs à cette fin où cette syntaxe indique déjà le filtrage.

(Au fait, j'aimerais une belle syntaxe pour le filtrage, comme notre belle syntaxe . . Pour illustrer mon propos ci-dessus, peut-être qu'un map - filter pourrait ressembler à 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

Désolé d'être hors sujet et je ne suis pas sûr que ce qui précède soit une bonne idée, mais je signale simplement qu'il pourrait y avoir une autre utilisation potentielle de la syntaxe de filtrage de compréhension if qui a une sémantique de filtrage)

Enfin - je suis un peu d'accord avec les observations de @tbreloff ci-dessus ... binaire ? est la syntaxe la plus compacte (et tout l'intérêt de ce fil est de faire une syntaxe compacte), et j'ai toujours trouvé if un choix quelque peu surprenant pour le filtrage du générateur.

@StefanKarpinski a écrit :

La syntaxe du modificateur if/for de style Perl/Ruby semble mieux se mélanger avec cela. En d'autres termes:
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
Il a également l'avantage d'avoir un précédent dans d'autres langages, ce que la syntaxe if-then sans fin ne semble pas avoir.

Et ce serait mieux pour la grammaire aussi.

Je pense que [x^2 if x % 3 == 0 for x = 1:100] devrait être :

[(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

Je pense que [x^2 if x % 3 == 0 for x = 1:100] devrait être :

Ce ne serait pas un générateur filtré. 2 if x renvoie 2 lorsque x est vrai, mais il doit également renvoyer quelque chose lorsque x est faux ; typiquement ce serait nothing . Cela donnerait donc un tableau de nombres et de riens. C'est en partie pourquoi if doit venir après for dans la syntaxe du générateur filtré.

Oui, tu as raison. Il faudrait peut-être l'écrire comme ça :

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

Afaics, ce serait valide analysable sans l'utilisation de parenthèses, cool !

Juste à y penser...

[ 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

Cela ressemble plus à la construction naturelle

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

Je viens de revoir ce julep en regardant autre chose.

Je souhaite toujours quelque chose comme le formulaire à une seule ligne if a then b ; Je trouve que le remplacement julien a && b est assez illisible même après l'avoir utilisé pendant plusieurs années : il n'y a tout simplement aucun moyen de le lire directement comme une phrase en anglais.

Je pense également que la nécessité d'expliquer l'idiome a && b aux nouveaux arrivants est un peu gênante alors que nous pourrions avoir une syntaxe alternative qui est évidente et seulement un peu plus longue.

il n'y a tout simplement aucun moyen de le lire directement comme une phrase en anglais

a && b se lit comme "a et b" comme dans "si a alors faites aussi b"
a || b se lit comme "a ou b" comme dans "a doit être vrai, sinon faire b"

Je sais ce qu'il fait et je l'utilise à l'occasion par souci de brièveté. Mais essayez comme je pourrais (comme mentionné, depuis plusieurs années maintenant), je ne peux pas voir "a et b" comme une phrase. C'est juste une légère dissonance cognitive à chaque fois.

En revanche, j'ai toujours trouvé que "a ou b" était assez lisible.

Curieusement, différents aspects de cela sont apparus deux fois aujourd'hui au travail.

Le matin, nous avons eu un Julia PR qui utilisait && au lieu de if ... end et j'ai souligné qu'en tant que lecteur de code (réviseur PR), cela demandait des efforts supplémentaires (et était facile à manquer ) branches qui peuvent ou non être exécutées. L'exemple était de la forme a() && b!()b! est extrêmement muté. (Dans ce cas, b!() a déplacé ou supprimé des fichiers dans le système de fichiers, ce qui semblait immédiatement dangereux, mais mon cerveau n'arrivait pas à comprendre que cela n'était problématique que lorsque !a() et que ce cas était en fait correctement protégé contre).

Dans l'après-midi, un autre ingénieur logiciel (qui ne connaît pas Julia) a souligné que, lorsqu'il parlait anglais avec des amis, il répondait parfois à la question du formulaire "Is it a or b " avec la réponse "oui". Seuls ses amis ingénieurs en logiciel comprendraient - tous les autres ne comprendraient pas du tout . Les gens normaux ne pensent tout simplement pas de cette façon. 🙂 Cela se rapporte un peu à mon point suivant (EDIT : et j'aurais dû dire, se rapporte à la réponse de Stefan ci-dessus, ce qui, pour beaucoup de gens, je ne pense pas que cela leur arriverait).

Ma position sur ce problème depuis le début est que l'utilisation && (ou || ) est une syntaxe courte pour la création de branches qui n'est lisible que par les personnes ayant une solide expérience en PL, et même alors ajoute un peu de charge cognitive/visuelle (simplement pour distinguer & vs && ). J'ai l'impression que lorsque je travaille dans des équipes multidisciplinaires (mélange de scientifiques et d'ingénieurs en logiciel), cela crée activement de la confusion pour la moitié de l'équipe. Même en tant qu'ingénieur logiciel, je pense que nous avons une étrange déconnexion entre le &(::Bool, ::Bool) --> Bool logique et le branchement &&(::Bool, ::Any) --> Any (oui, ce dernier n'est pas vraiment une fonction, mais j'espère que vous comprenez mon point) . En dehors des types eux-mêmes, chez Julia, je m'attends généralement à ce que le premier soit "fonctionnel" tandis que la dernière forme implique souvent des effets secondaires potentiels - en particulier dans la seconde expression.

EDIT : en y réfléchissant davantage, le problème ici concerne uniquement les effets secondaires et le déroulement du programme. Il est assez facile pour tout le monde de comprendre que l'utilisation "fonctionnelle" de && est une optimisation de & . Il est relativement difficile de concilier qu'ils sont entièrement différents pour les expressions non pures.

Dans certains cas, je pense que la "précédence" est plus claire avec 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

De plus, la coloration syntaxique dans les éditeurs aiderait à marquer if au début de l'expression.

Il a également l'avantage d'avoir un précédent dans d'autres langages, ce que la syntaxe if - then sans end ne semble pas avoir.

Il convient de noter qu'il existe de nombreux précédents pour la syntaxe if-then-else :

Et cette syntaxe peut être utilisée pour les one-liners dans toutes les langues ci-dessus.

Je suis au courant de cette discussion depuis une heure, alors pardonnez-moi si cela a été suggéré.

Il me semble que les options de court-circuit de '&&' et '||' sont utilisés parce que nous voulons des instructions if simples sur une seule ligne, sans point-virgule. Mais le court-circuit semble être une solution qui crée un autre problème : en tant que humam, il est difficile de comprendre et d'analyser cette syntaxe sans l'avoir vue auparavant, ou en sachant que la deuxième expression n'est évaluée que lorsque cela est nécessaire. La lecture non intuitive (en tant qu'humain) semble être due à la fois à des imperfections visuelles et logiques avec court-circuit. Il semble même qu'après avoir compris ce que cela signifie, il peut être plus difficile que nécessaire de le lire.

Si je ne me trompe pas, les deux problèmes pourraient être résolus avec une macro :

@if résultat de la condition

La négation peut être manipulée avec un ! avant la condition, ou alternativement une macro @ifnot . C'est juste moi, ou est-ce sans ambiguïté pour l'ordinateur, facile à lire pour l'humain, et tout en une seule ligne ?

Il semble même qu'après avoir compris ce que cela signifie, il peut être plus difficile que nécessaire de le lire.

^ Je suis entièrement d'accord avec cela.

@if résultat de la condition

Vous pouvez déjà faire ce qui suit, qui ressemble presque au même :

if condition result end

Vous trouverez ci-dessous une macro pour la syntaxe complète if-then-else. Cependant, étant donné que if et else sont des mots clés réservés, la macro utilise If , Then et Else la place.

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")

Et ici, nous pouvons voir foo en action :

julia> foo(3)
greater than zero

julia> foo(-3)
less than zero

Je préférerais quelque chose comme

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

when aurait moins de priorité que = et fonctionnerait de droite à gauche.

Vous pouvez déjà faire ce qui suit, qui ressemble presque au même :

if condition result end

je ne le savais pas ! J'ai toujours pensé qu'il fallait les points-virgules là où il y a normalement une nouvelle ligne. Donc dans mon cas, la syntaxe

if condition result end

rend complètement l'utilisation de && redondante, et donc il n'y a pas de problème ! Je vois qu'on peut même faire ceci :

if condition result_1 else result_2 end

Dans ce cas, ajouter le mot-clé end est probablement plus facile que de créer une macro. Mais merci d'avoir pris le temps de le faire quand même ^_^ Est-ce une bonne idée d'ajouter la possibilité aux instructions if d'une ligne dans la documentation ? Je vois que si l'on fait ?If<enter> le résultat est déjà pas mal de lignes... Mais j'ai l'impression que cette fonctionnalité devrait être davantage annoncée.

En ce qui concerne la discussion initiale, je suis en faveur de l'ajout de "Si x alors y", même si je le trouve un peu redondant avec la version en une ligne de "si". Mais bon, écrivez du code comme bon vous semble, n'est-ce pas ?

Cette page vous a été utile?
0 / 5 - 0 notes