Julia: Mini Julep: Wenn x dann y

Erstellt am 16. Mai 2016  ·  53Kommentare  ·  Quelle: JuliaLang/julia

In verschiedenen Diskussionen wurde vorgeschlagen, folgende Syntax zuzulassen:

if x then y

Als abgekürzte „if“-Anweisung und als Alternative zum Üblichen:

x && y

Syntax, die den kurzschließenden Operator && nutzt, um y bedingt auszuführen (wobei y oft andere Nebeneffekte enthält und nicht unbedingt Bool ).

Die Hauptvorteile dieses if-then -Konstrukts sind: besser lesbarer Code, der sich weniger auf den Missbrauch && verlässt und formal ein "if"-Anweisungsformular enthält, das kein end erfordert Stichwort.

Neulich fiel mir ein, dass diese Syntax auch ein praktisches Mittel zur Implementierung von #550 darstellen würde, das so aussehen würde:

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

Unter Berufung auf die Tatsache, dass if-then kein end -Schlüsselwort benötigt, das wir wahrscheinlich sowieso in irgendeiner Form benötigen würden, selbst wenn wir Wachen im Python-Stil verwenden würden:

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

Um es klar zu sagen, würde die Julia-Wächter-Syntax im Wesentlichen eine Umschreibung von:

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

zu

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

Als klarstellende Anmerkung würde dies die Schutzsyntax auf der _generator_-Ebene zulassen, im Gegensatz zu nur der _comprehension_-Ebene (die auch zu dem passt, was Python zulässt).

julep

Hilfreichster Kommentar

Vielleicht bin ich in der Minderheit, da andere Sprachen diesen Ansatz gewählt haben, aber ich fand die Aktion vor der Bedingung immer sehr seltsam, zB println("positive") if x > 0 . Ich denke, es ist prägnanter als if x > 0 println("positive") end , aber zumindest für mich geht es auf Kosten der Lesbarkeit.

Ich stelle es mir wie ein Gespräch vor:

Julia: "Ich drucke einen String..."
Harald: „Großartig!“
Julia: "...aber nur wenn eine Bedingung erfüllt ist."
Harald: „Oh. :(“

gegen

Julia: "Wenn eine Bedingung erfüllt ist, drucke ich einen String."
Harold: "Okay, cool."

Alle 53 Kommentare

Die Perl/Ruby-artige if/for-Modifizierer-Syntax scheint sich besser damit zu mischen. Mit anderen Worten:

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

Es hat auch den Vorteil, Präzedenzfälle in anderen Sprachen zu haben, was die if - then ohne end Syntax nicht zu haben scheint.

Nur eine Randnotiz zum Issue-Management: #6823 behandelt genau dieses Thema. Irgendwann wurde es kommentarlos geschlossen, ich fragte nach, warum es geschlossen wurde, weil es offensichtlich keinen Konsens gegeben hatte, es zu schließen, aber ich bekam nie eine Antwort. Es scheint effizienter zu sein, Ausgaben wie #6823 nicht zu schließen, da sich diese Diskussionen sonst nur im Kreis drehen und alle Punkte der ursprünglichen Ausgabe erneut wiederholt werden. Wahrscheinlich wäre es sinnvoll gewesen, den Titel von #6823 irgendwann zu ändern und diesen dann hier hinzuzufügen.

Ja, guter Punkt. Tatsächlich scheint #6823 mitten in der Diskussion zu sein und hätte wahrscheinlich nicht geschlossen werden sollen.

Vielleicht bin ich in der Minderheit, da andere Sprachen diesen Ansatz gewählt haben, aber ich fand die Aktion vor der Bedingung immer sehr seltsam, zB println("positive") if x > 0 . Ich denke, es ist prägnanter als if x > 0 println("positive") end , aber zumindest für mich geht es auf Kosten der Lesbarkeit.

Ich stelle es mir wie ein Gespräch vor:

Julia: "Ich drucke einen String..."
Harald: „Großartig!“
Julia: "...aber nur wenn eine Bedingung erfüllt ist."
Harald: „Oh. :(“

gegen

Julia: "Wenn eine Bedingung erfüllt ist, drucke ich einen String."
Harold: "Okay, cool."

@ararslan : Ich bin nicht anderer Meinung, was einer der Gründe ist, warum diese Funktion trotz des Stands der Technik in Ruby und Perl nicht in Julia enthalten ist. Es lässt sich jedoch viel besser mit der Modifikator-Syntax for für Generatoren und Verständnis kombinieren, weshalb ich es hier erwähnt habe.

@StefanKarpinski Ja, stimmte zu, es passt besser zu denen. Ich hänge aber immer noch hoffnungslos an Bedingungen, die Handlungen vorangehen. :smile: (Aber wie ich in letzter Zeit oft gesagt habe, ist meine Meinung nicht wirklich wichtig; ich bin nur irgendein Typ.)

Ich nehme an, wenn Sie so etwas hätten

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

dann ist es nicht sofort klar, dass Sie ein Verständnis / einen Generator / ein Thingamajig starten, weil es sich auch so liest, als ob es gruppiert werden könnte

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

dh, wenn eine Bedingung dann Generator. Ich hätte nichts dagegen

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

Ich denke, wenn die Bedingung der Aktion in einem Generator folgen würde, würde ich ein anderes Schlüsselwort als if bevorzugen, zum Beispiel where . Dann liest es sich fast wie eine SQL-Abfrage, zB

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

Ich denke , where macht es ein wenig klarer , dass Sie die Werte sind Filterung x , hergestellt von der for als if der Fall ist.

Es erscheint mir schöner, den Datenfluss in eine Richtung zu haben, allerdings in diesem Fall von rechts nach links statt von links nach rechts.

Können Sie erläutern, was Sie damit meinen?

Das for 1:n „erzeugt“ Werte, das if x % 3 == 0 filtert sie und das x^2 transformiert sie – Generatoren fließen bereits von rechts nach links und um diesen Fluss aufrechtzuerhalten, muss der Filter hineingehen Mitte. Wenn die if -Klausel rechts von der for -Klausel steht, "fließen" die Daten von der Mitte nach ganz rechts und dann nach ganz links, was seltsam ist. Wenn die Klausel if links steht, „fließen“ die Daten von ganz rechts nach ganz links in die Mitte. Ich weiß, dass SQL die where -Klausel rechts neben die Tabellennamen und die Ausdrücke links setzt – weil sich das eher wie Englisch liest – aber ich fand das immer lästig zu lesen und ich denke, dass das Lesen wie Englisch ist ist keine Heuristik, die beim Design von Programmiersprachen zu weit getrieben werden sollte.

Dinge, die ich an if x then y nicht mag:

  1. Es führt das neue Schlüsselwort then ein.
  2. Es ist kürzer if x y end zu schreiben als if x then y ; x && y ist sogar noch kürzer.
  3. Das Schlüsselwort then wird in Sprachen häufig für die genau entgegengesetzte Art von Syntax verwendet: eine mehrzeilige if -Syntax, die ein end -Schlüsselwort erfordert (oder fi in bash , igitt).

Oh ja, ich verstehe jetzt, was du mit dem Fluss meinst. Das macht Sinn. Danke für die Erklärung!

Wäre es seltsam, das zu können

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

und _nicht_ tun können

println("positive") if x > 0

?

Alles gute Punkte.

Ich mag die Syntax, die @StefanKarpinski erstmals in seinem ersten Kommentar vorgeschlagen hat, wirklich sehr. Ich interessiere mich hauptsächlich für Bedingungsgeneratoren, mit einer allgemeineren Kurzform _if_-Form als Bonus.

In Bezug auf Generatoren habe ich gelesen, dass if (oder where - dazu habe ich keine Meinung) Teil des Bereichs sein sollen ... es erstellt einen Iterator x = 1:10 if/where x % 2 == 0 , der wird dann mit dem Ausdruck auf der linken Seite kombiniert, um ein Array (oder einen Generator) zu erstellen.

In gewissem Sinne ist x = 1:10 where x % 2 == 0 selbst ein Generator für eine Art Iterable. Dies könnte eine eigenständige Syntax sein, oder?

Ich habe das Gefühl, dass das Filtern irgendwie eine andere Operation ist als die bedingte if a then b -Anweisung. Die Filterung wirkt auf den Iterationsbereich. Wenn if a then b mit dem Ausdruck auf der linken Seite des Generators kombiniert wird, würde ich erwarten, dass nothing in den Fällen ausgegeben wird, in denen a false war. Vergleichen Sie, was logischerweise passiert, wenn ich Klammern hinzufüge:

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

Nehmen wir die Beispiele von @ararslan , wenn wir erlauben

println("positive") if x > 0

dann IMHO folgt daraus

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

sollte wahrscheinlich nothing, nothing, 9, nothing, nothing, 36, ... ausgeben

Wenn wir schließlich eine Bedingung mit der Abkürzung if übernehmen würden, stimme ich für die Bedingung vor der Aussage, aus den Gründen, die in @ararslans erstem Beitrag dargelegt wurden - da es der Prinzipal der am wenigsten überraschenden beim Lesen des Codes ist. (Denken Sie daran, wenn sie sagen, dass Code mehr gelesen als geschrieben wird, dann ist if a then b eine bessere Syntax als a && b , auch wenn letzteres kürzer ist). Es bedeutet auch, dass die zwei möglichen Arten von if innerhalb des Generators unterschiedlich sind – ganz links – mit dem Ausdruck – oder ganz rechts – mit dem Bereich.

Was die Tradition in Ruby/Perl betrifft, denke ich, dass es besser ist, zu versuchen, die beste Lösung zu finden, als sich von der Tradition festfahren zu lassen. Wenn es funktioniert und sich natürlich anfühlt, werden die Leute es mögen.

Wenn wir if/where in Bereichen haben, müssen wir dann darauf achten, dass der Bereich für mehrdimensionale Generatoren kartesisch bleibt?

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

Das ist irgendwie cool und irgendwie schrecklich!

Ich habe das Gefühl, dass das Filtern irgendwie eine andere Operation ist als die bedingte if a then b-Anweisung.

Ja! Genau diesen Kommentar wollte ich gerade posten. Die Filterung wirkt sich auf den Iterator als Ganzes aus und ist nicht Teil des berechneten Ausdrucks darin.

Ich habe auch das gleiche Gefühl wie @andyferris, dass das if zwischen dem Ausdruck und der Iteration den Wert des Ausdrucks und nicht die Form der Iteration zu "transformieren" scheint und nogthing erzeugen sollte, wenn die Bedingung ist nicht erfüllt (aber ich kann durch Python/Haskell-Verständnisse verwöhnt werden).

Offensichtlich würde x if false zu nothing ausgewertet werden, wenn es sich nicht im Kontext eines Generatorausdrucks befindet. Es wäre vollkommen vernünftig, [x^2 if x % 3 == 0 for x=1:100] zu unterstützen, aber nicht x if y allein.

Ich persönlich würde end lieber weglassen, wenn es nur eine Anweisung gibt.

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

Wenn es kein end gibt, könnte es davon ausgehen, dass es nur einen Ausdruck gibt. Ich nehme an, das wurde schon ausführlich diskutiert?
Ich bemerke, dass ich es vorziehen würde, kein Semikolon nach der Bedingung zu haben - nach dem Ausdruck ... _vielleicht_ ... Ich würde es aber nicht mögen.

Das wäre mir viel lieber, als zwei verschiedene Syntaxen für eine ähnliche Form der if-Anweisung zu haben;if x; ...; end und if x then; ... . _(Edit: if condition then action ist mir ans Herz gewachsen.)_

Es wäre durchaus sinnvoll, [x^2 if x % 3 == 0 for x=1:100] zu unterstützen, aber nicht x if y allein.

@StefanKarpinski Da bin ich voll dabei. Jedoch...

Wenn die if-Klausel links steht, "fließen" die Daten von ganz rechts nach ganz links in die Mitte.

Ich lese x^2 if x % 2 == 0 for x in 1:10 als x^2 where x % 2 == 0 for each x in 1:10 , was für mich aufgrund des Verständnisses Sinn ergibt; Sie interessieren sich am meisten für die Transformation.
Bei SQL-Abfragen gilt derselbe Punkt, oder?

Ich denke daher nicht, dass es ganz richtig ist, den "Generator" als Ausgangspunkt für das Lesen zu haben, _für ein Verständnis_. Eine for-Schleife dagegen ... Das macht mehr Sinn.

Ich persönlich würde end lieber weglassen können, wenn es nur eine Anweisung gibt.

Ich habe dies vor langer Zeit vorgeschlagen, aber es hat keine Anklang gefunden: https://github.com/JuliaLang/julia/issues/1657. Dies wäre eigentlich eine relativ unterbrechungsfreie Änderung, da es seltsam und selten wäre, einen solchen Schreibcode zu sehen:

if cond body
end

Was halten Sie davon, do Blöcke anstelle von then ? dh: if x do y end

Nur eine kleine Nebenbemerkung: Ich sehe keine Möglichkeit, dass if x y allein (dh außerhalb eines Generators) ohne einen ausgewachsenen Julia-Parser in einem Editor korrekt gehandhabt werden könnte, da Sie es sein müssen in der Lage zu bestimmen, wie viele Token auf if folgen. Ich denke an vim, aber ich nehme an, andere Redakteure könnten in der gleichen Situation sein. Dasselbe könnte für y if x , aber ich bin mir nicht sicher (vollständige Offenlegung: Ich mag y if x an sich auch wirklich nicht; ich bin nicht grundsätzlich gegen if x y , aber denke, dass es auch für Menschen etwas schwierig sein kann, nicht nur für Redakteure zu analysieren).

@diegozea Dasselbe Problem, denke ich. Ich würde immer noch if x y bevorzugen.

@carlobaldassi Es gibt einige Dinge, die Sie tun könnten, um Menschen das Parsen zu erleichtern.

Sie könnten diese einzelne Anweisung erzwingen, wenn zwischen der Bedingung und dem Ausdruck kein Zeilenumbruch vorhanden wäre.
Ich bin mir jedoch nicht sicher, ob ich das für lange Ausdrücke tun möchte.

Alternativ könnten Sie einen Zeilenumbruch nach dem Ausdruck erzwingen, wenn nach der Bedingung ein Zeilenumbruch vorhanden war; Folgendes würde also nicht kompilieren, aber natürlich eine klare Fehlermeldung geben:

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

Aber das würde:

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

und das würde:

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

if some_condition(A, B)
   N *= 2

Dies würde auch verhindern, dass Sie diese Art von Fehlern machen:

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

    return y * 2

Ich denke, das größte Argument für if x then y , das immer noch gegenüber jeder anderen Syntax überzeugt, ist die Lesbarkeit . Dass if x y end , if x y oder x && y kürzer sind, ist in meinem Buch irrelevant (abgesehen von der Tatsache, dass wir über einen trivialen Unterschied von 1-5 Zeichen sprechen), weil keines davon sind fast so klar wie if x then y . Es vermeidet auch Parsing-Probleme des Editors oder mögliches Brechen von früherem Code. Es ist nur eine schöne, saubere, kurze Syntax für kurze if-Anweisungen.

Ich erkenne jedoch die potenzielle Verwirrung bei der Verwendung von if-then im Generatorfall an; Da stimme ich dem zu

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

ist am deutlichsten, zu erkennen, dass die Ausdrucksstruktur ist

generated_value_expr  value_generator_expr  =>  generator_expression

[generator_filter_expr]  for_generator_expr  => value_generator_expr

dh generator_filter_expr wird direkt auf die aus for_generator_expr generierten Werte angewendet, bevor ungefilterte Werte an generated_value_expr übergeben werden.

Ich denke, die Unterscheidung ist hier wichtig, weil es nicht dieselbe Logik ist, die es erlauben würde

println("positive") if x > 0 

TL;DR: Wir sollten x^2 if x % 3 == 0 for x = 1:100 für gefilterte Generatoren haben, aber die gleiche Syntaxlogik gilt nicht für println("hey") if x > 0 , daher sollten wir immer noch if x then y für die Kurzform in Betracht ziehen if-Syntax. Obwohl die beiden Ideen hier offensichtlich jetzt völlig unabhängig voneinander sind.

@ H-225 Das erscheint mir seltsam und letztendlich un-julianisch, besonders mit der Aktion in einer neuen Zeile ohne end .

Es wäre immer noch ein Alptraum für einen Redakteur zu parsen, weil es Redakteuren (wie Vim) egal ist, was eine Bedingung oder Aktion ist und was nicht – tatsächlich haben sie ohne einen Julia-Parser keine Möglichkeit, es zu wissen – sondern sie Achten Sie auf die Platzierung von Dingen wie if und end . Ich denke, es wäre außerordentlich schwierig, Vim dazu zu bringen, zu erkennen, dass end in diesem Szenario nicht benötigt wird. Mir ist klar, dass es kein gutes Argument für eine Designentscheidung ist, es den Redakteuren zu erleichtern, ich sage nur.

Definitiv :-1: für if x y von mir. Ich würde if x then y dem vorziehen, da es für mein kleines Gehirn einfacher zu analysieren ist. :stuck_out_tongue_winking_eye:

Gibt es einen Grund, den ternären Fragezeichenoperator nicht einfach auch für die if-Anweisung zu verwenden? Sie können damit bereits eine if-Anweisung nachahmen

condition ? if_condition_true_eval_expr : nothing

Warum machen Sie es nicht einfach so, dass, wenn Sie keinen Doppelpunkt einfügen, es eine if-Anweisung ist, dann hätten Sie es einfach getan

condition ? if_condition_true_eval_expr

Auf diese Weise müssen Sie keine neuen Schlüsselwörter eingeben, würde das funktionieren?

@esproff Lustigerweise wollte ich das Gegenteil vorschlagen: die If-Then-Idee in diesem Julep auf einen einzeiligen If-Then-Else-Ausdruck erweitern

if cond then a else b

wobei die else-Klausel optional ist. Es könnte sogar auf cond ? b : c . Für mich dreht sich alles darum, weg von der C-ähnlichen Dreiheit und hin zu menschenlesbarerem Code. (Ich habe condition ? a : nothing definitiv schon einmal verwendet - es scheint ein Hack zu sein (weil es so war, das nothing war aus irgendeinem obskuren Grund wichtig) und es ist verwirrend für andere Leute es zu lesen).

Aber warum können wir natürlich nicht alle diese Ideen gleichzeitig haben?

@andyferris Ja, das ist der andere Weg, Pythonic. Ich denke, es hängt davon ab, wie knapp Sie sein wollen, Mathematiker scheinen im Allgemeinen Prägnanz zu schätzen, aber ehrlich gesagt wäre ich mit beiden zufrieden, solange ich nicht das Klobige verwenden muss

if condition; eval_expr; end

aber ehrlich gesagt wäre ich mit beiden zufrieden, solange ich nicht das klobige verwenden muss

if condition; eval_expr; end

In der Tat!

Für das, was es wert ist, mag ich die x & & y-Notation und sehe es nicht als Missbrauch an.

Ich persönlich bevorzuge eine operatorbasierte Lösung, die false nicht zurückgibt, wenn die erste Anweisung falsch ist. Ich wäre mit so ziemlich allem zufrieden, obwohl ich a ?: b als Zwei-Argument-Version des ternären Operators mag.

Die ? -Idee wurde ziemlich ausführlich in #6823 diskutiert, es könnte sich lohnen, diese Diskussion noch einmal zu lesen.

Ich bin von dieser Diskussion hierher gekommen, dachte aber, dass dies ein besserer Ort für einen Kommentar ist. Ich denke, dass if a then b und die Verwendung von nur ? ohne : etwas verwirrend wären, aber ich würde mich nicht beschweren, solange sie die gleiche Funktionalität bieten.

Ich stimme @EricForgy zu. Vielleicht bin ich an dieser Stelle nur an sie gewöhnt, aber für mich fühlt sich die Verwendung && und || auf diese Weise für Julia idiomatisch an, insbesondere für die Fehlerprüfung (zB x || throw(y) ). Sie wirken überhaupt nicht mehrdeutig oder unlesbar. Außerdem verstehe ich nicht wirklich, warum es wichtig sein sollte, dass x && y false $ zurückgibt, wenn x falsch ist, da es wahrscheinlich sowieso nicht am Ende einer Funktion verwendet werden sollte , wo es den Rückgabewert der Funktion beeinflussen würde.

Ternäre im C-Stil sind ziemlich allgegenwärtig; Ich würde argumentieren, dass nicht nur Mathematiker diese Syntax schätzen. Die einzige Sprache, die mir spontan einfällt, die Ternaries hat, aber den C-Stil nicht unterstützt, ist Python, und FWIW verachte ich Python-Ternaries. condition ? action1 : action2 ist sowohl kompakt als auch lesbar, solange Sie Leerzeichen verwenden und Zeilenlängen respektieren. Für längere Zustände und Aktionen sollte man verwenden

if condition
    somelongaction1
else
    somelongaction2
end

sowieso für die Lesbarkeit.

In Bezug auf then , den Punkt dieser Diskussion, FWIW würde ich es wahrscheinlich nicht verwenden, selbst wenn es implementiert wäre, da sich && und || wiederum idiomatisch für mich anfühlen. Obwohl ich then sofort über if x y , x ? y oder x ? y : nothing nehmen würde.

Ich persönlich bevorzuge viel y if x . Es mag wie der falsche Weg erscheinen, aber es gibt Vorrang vor Ruby und Perl: Die mathematische Groß- und Kleinschreibung hat es so

image

Ich _gerne_ dafür, && oder || zu verwenden, da ich mich nie erinnern kann, dass x && y = z nicht so analysiert, wie ich es erwarte. Ich denke, es hat eine höhere kognitive Belastung als y if x ; das gilt auch für if x y .

IMO, x ? y _smells_ wie ein Syntaxfehler, unabhängig davon, ob es tatsächlich gültig ist.

x ?? y vielleicht? x ?: y ist eine GNU-C-Erweiterung, die x ? x : y bedeutet, also könnten ?? und ?: Versionen mit niedriger Priorität von && und || sein

Meine bevorzugte Reihenfolge: y if x == x ?? y < if x then y < x && y < x ? y < if x y .

FWIW. Ich bevorzuge die Knappheit und klare Trennung des Codes mit ? , && und || , obwohl die Syntax cond ? expr klarer sein könnte als die && .

Ich mache gerne häufig goodcondition || return -Flows, was mit if-Anweisungen nicht einfach ist. Ich möchte das nicht verlieren (oder dazu gemobbt werden, es nicht zu benutzen)

Für ternäre ohne die : könnte es nett sein, knappe if / elseif Blöcke ohne eine else Bedingung zuzulassen:

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

und man könnte sich vorstellen, dies auf switch-Anweisungen zu erweitern:

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

Auf die Lesbarkeit kommt es an. Für viele kurze Bedingungen/Aktionen ist es viel besser lesbar (mit sauberem Abstand!!), Bedingungen/Aktionen in aufeinanderfolgenden Zeilen mit klaren Trennzeichen aneinanderreihen zu können.

Für Generatoren würde ich where oder when der Umnutzung if vorziehen, da es sich um einen Filter und nicht um eine Bedingung handelt:

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

Ich denke, es ist klarer, dass dies x = [i^2 for i in filter(..., 1:10)] bedeutet.

Ich möchte anmerken, dass ich seit der Diskussion darüber nichts mehr gegen if condition then action einwenden würde - es ist mir ziemlich ans Herz gewachsen.
Julia neigt dazu, sich auf die "wortreichere" Seite zu stützen, mit function und end usw., also denke ich, dass es genau passen würde. Es ist auch ein wenig irritierend, Klammern hinzufügen zu müssen Ausdrücke, wenn Sie zwischen der condition && action -Syntax hin und her gehen.

Bezüglich der Perl/Ruby-Syntax „action if condition“: Ich mag diese Syntax wirklich, und obwohl ich zustimme, dass sie die Lesbarkeit verringern kann, wenn sie falsch verwendet wird, glaube ich auch, dass sie manchmal die Lesbarkeit _erhöht_.

Beispielsweise:

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

Nachdem Sie „throw domain error if“ gelesen haben, wissen Sie bereits, dass das Folgende eine Plausibilitätsprüfung der Eingabe sein wird. Sie können dann zur nächsten Zeile springen, wenn Ihnen die Einzelheiten der Bedingung nicht wichtig sind.

Der vorherige Satz ist ein Beispiel dafür, wie diese Konstruktion häufig in natürlicher Sprache vorkommt. Die Aktion "Springe zur nächsten Zeile" steht an erster Stelle, und die weniger wichtige Aktion "Wenn es dich nicht interessiert" kommt in einem Nebensatz. Auch hier kann der Leser möglicherweise ungefähr erraten, was auf das Wort „wenn“ folgen wird, ohne den Satz tatsächlich bis zum Ende lesen zu müssen.

(Ich werde auch einen selbstreferenziellen Beispielsatz geben, wenn mir einer einfällt.)

Als alter Perl-Handhaber bin ich mit dieser Syntax einverstanden, aber ich denke, dass es für andere, die keinen Perl-Hintergrund haben, schwer zu verkaufen sein wird. Ein Argument dafür ist, dass es mit der Filtersyntax in Comprehensions übereinstimmt. Ein Argument dagegen ist, dass es seltsam ist, ein Konstrukt zu haben, bei dem die Auswertungsreihenfolge nicht von links nach rechts ist. Verständnis hat natürlich genau das, also 🤷‍♂️

Eine verwandte Frage für mich ist dann: Verallgemeinern wir Verzweigung oder Filterung? Dies ist eine Verallgemeinerung der Verzweigungs- if -Semantik (und -Syntax), daher wäre es vielleicht unglücklich, die Syntax von Comprehensions/Generatoren für diesen Zweck auszuleihen, wo diese Syntax bereits auf Filterung hinweist.

(Übrigens hätte ich gerne eine nette Syntax zum Filtern, wie unsere nette . -Syntax. Um meinen Punkt oben zu veranschaulichen, könnte ein map - filter vielleicht wie f.(a) if g.(a) aussehen

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

Entschuldigen Sie, dass ich vom Thema abweiche, und ich bin mir nicht sicher, ob das Obige überhaupt eine gute Idee ist, aber ich möchte nur darauf hinweisen, dass es eine andere potenzielle Verwendung der Comprehension-Filtering- if -Syntax geben könnte, die Filtersemantik hat)

Schließlich - ich stimme den obigen Beobachtungen von @tbreloff irgendwie zu ... binär ? ist die kompakteste Syntax (und der ganze Sinn dieses Threads besteht darin, eine kompakte Syntax zu erstellen), und ich habe immer if gefunden

@StefanKarpinski schrieb:

Die Perl/Ruby-artige if/for-Modifizierer-Syntax scheint sich besser damit zu mischen. Mit anderen Worten:
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
Es hat auch den Vorteil, Präzedenzfälle in anderen Sprachen zu haben, was die Wenn-Dann-Syntax ohne Ende nicht zu tun scheint.

Und es wäre auch besser für die Grammatik.

Ich denke, [x^2 if x % 3 == 0 for x = 1:100] sollte sein:

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

Ich denke, [x^2 if x % 3 == 0 for x = 1:100] sollte sein:

Das wäre kein gefilterter Generator. 2 if x gibt 2 zurück, wenn x wahr ist, aber es muss auch etwas zurückgeben, wenn x falsch ist; normalerweise wären das nothing . Das würde also eine Reihe von Zahlen und Nichts ergeben. Das ist teilweise der Grund, warum if for kommen muss.

Ja, du hast recht. Vielleicht sollte man es so schreiben:

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

Afaics, das wäre ohne die Verwendung von Klammern gültig parsbar, cool!

Ich denke nur...

[ 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

Dies ist dem natürlichen Konstrukt ähnlicher

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

Ich habe gerade diesen Julep wieder gesehen, als ich etwas anderes betrachtete.

Ich wünsche mir immer noch so etwas wie das einzeilige Formular if a then b ; Ich finde den julianischen Ersatz a && b ziemlich unlesbar, selbst nachdem ich ihn mehrere Jahre benutzt habe: Es gibt einfach keine Möglichkeit, ihn direkt als englischen Satz zu lesen.

Ich finde auch, dass die Notwendigkeit, Neulingen die Redewendung a && b zu erklären, irgendwie peinlich ist, wenn wir eine alternative Syntax haben könnten, die selbstverständlich und nur wenig länger ist.

Es gibt einfach keine Möglichkeit, es direkt als englischen Satz zu lesen

a && b liest sich als "a und b" wie in "wenn a dann auch b tut"
a || b liest sich als "a oder b" wie in "a muss wahr sein, sonst tue b"

Ich weiß, was es tut, und ich benutze es gelegentlich der Kürze halber. Aber so sehr ich es auch versuche (wie erwähnt, seit einigen Jahren), ich kann "a und b" nicht als Satz sehen. Es ist jedes Mal nur eine leichte kognitive Dissonanz.

Im Gegensatz dazu fand ich "a oder b" immer ziemlich lesbar.

Witzigerweise kamen heute bei der Arbeit zwei verschiedene Aspekte davon zur Sprache.

Am Morgen hatten wir eine Julia-PR, die && anstelle von if ... end verwendete, und ich wies darauf hin, dass es als Codeleser (PR-Reviewer) zusätzlichen Aufwand erforderte (und leicht zu übersehen war). ) Branches, die ausgeführt werden können oder nicht. Das Beispiel hatte die Form a() && b!() , wobei b! extrem mutate-y ist. (In diesem Fall hat b!() Dateien im Dateisystem verschoben oder gelöscht, was sofort gefährlich erschien, aber mein Gehirn konnte nicht herausfinden, dass dies nur problematisch war, wenn !a() und dass dieser Fall wurde eigentlich korrekt davor gewarnt).

Am Nachmittag wies ein anderer Software-Ingenieur (der Julia nicht kennt) darauf hin, dass er manchmal die Frage in der Form „Is it a or b “ beantwortet, wenn er mit Freunden Englisch spricht “ mit der Antwort „ja“. Nur seine befreundeten Softwareentwickler würden es verstehen – alle anderen würden es überhaupt nicht verstehen. Normale Menschen denken einfach nicht so. 🙂 Dies bezieht sich ein wenig auf meinen nächsten Punkt (EDIT: und ich hätte sagen sollen, bezieht sich auf Stefans obige Antwort, von der ich glaube, dass viele Leute nicht darauf kommen würden).

Meine Haltung zu diesem Thema ist die ganze Zeit, dass die Verwendung && (oder || ) eine kurze Syntax für die Verzweigung ist, die nur von Leuten mit einem starken PL-Hintergrund lesbar ist und selbst dann ein wenig hinzufügt kognitive/visuelle Belastung (einfach um & vs. && zu unterscheiden). Ich habe das Gefühl, dass die Arbeit in multidisziplinären Teams (Mischung aus Wissenschaftlern und Softwareentwicklern) für die Hälfte des Teams aktiv verwirrend ist. Selbst als Softwareentwickler habe ich das Gefühl, dass wir eine seltsame Trennung zwischen dem logischen &(::Bool, ::Bool) --> Bool und dem verzweigten &&(::Bool, ::Any) --> Any haben (ja, letzteres ist eigentlich keine Funktion, aber Sie verstehen hoffentlich, was ich meine). . Abgesehen von den Typen selbst erwarte ich bei Julia typischerweise, dass die erstere "funktional" ist, während die letztere Form häufig potenzielle Nebenwirkungen beinhaltet - insbesondere im zweiten Ausdruck.

BEARBEITEN: Wenn Sie mehr darüber nachdenken, dreht sich das Problem hier ausschließlich um Nebenwirkungen und den Programmablauf. Es ist ziemlich einfach für jeden zu verstehen, dass die "funktionale" Verwendung von && eine Optimierung von & ist. Es ist relativ schwierig in Einklang zu bringen, dass sie für nicht reine Ausdrücke völlig unterschiedlich sind.

In einigen Fällen denke ich, dass "Vorrang" mit if a then b klarer ist:

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

Auch die Syntaxhervorhebung in Editoren würde helfen, if am Anfang des Ausdrucks zu markieren.

Es hat auch den Vorteil, Präzedenzfälle in anderen Sprachen zu haben, was die if - then ohne end Syntax nicht zu haben scheint.

Es sollte beachtet werden, dass _es viele_ Präzedenzfälle für die if-then-else -Syntax gibt:

Und diese Syntax kann für Einzeiler in allen oben genannten Sprachen verwendet werden.

Ich bin mir dieser Diskussion seit einer ganzen Stunde bewusst, also verzeihen Sie mir, wenn dies vorgeschlagen wurde.

Es scheint mir wie die Kurzschlussoptionen von '&&' und '||' werden verwendet, weil wir einfache if-Anweisungen in einer Zeile ohne Semikolons wollen. Aber das Kurzschließen scheint eine Lösung zu sein, die ein weiteres Problem schafft: Als Mensch ist es schwierig, diese Syntax zu verstehen und zu analysieren, ohne sie vorher gesehen zu haben oder zu wissen, dass der zweite Ausdruck nur ausgewertet wird, wenn es nötig ist. Das nicht intuitive Lesen (als Mensch) scheint sowohl auf visuelle als auch auf logische Unvollkommenheiten mit Kurzschlüssen zurückzuführen zu sein. Es scheint sogar, dass es, nachdem man weiß, was es bedeutet, schwerer zu lesen ist, als es sein sollte.

Wenn ich mich nicht irre, könnten beide Probleme mit einem Makro behoben werden:

Ergebnis der @if- Bedingung

Eine Negation könnte mit einem ! behandelt werden. vor der Bedingung oder alternativ ein @ifnot -Makro. Das bin nur ich, oder ist das für den Computer eindeutig, für den Menschen gut lesbar und alles in einer Zeile?

Es scheint sogar, dass es, nachdem man weiß, was es bedeutet, schwerer zu lesen ist, als es sein sollte.

^ Dem stimme ich ausdrücklich zu.

Ergebnis der @if- Bedingung

Sie können bereits Folgendes tun, was fast gleich aussieht:

if condition result end

Unten ist ein Makro für die vollständige if-then-else-Syntax. Da jedoch if und else reservierte Schlüsselwörter sind, verwendet das Makro stattdessen If , Then und Else .

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

Und hier können wir foo in Aktion sehen:

julia> foo(3)
greater than zero

julia> foo(-3)
less than zero

Am liebsten wäre mir sowas

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

when hätte weniger Vorrang als = und würde von rechts nach links betrieben.

Sie können bereits Folgendes tun, was fast gleich aussieht:

if condition result end

Das wusste ich nicht! Ich dachte immer, dass man die Semikolons braucht, wo normalerweise ein Zeilenumbruch ist. Also in meinem Fall die Syntax

if condition result end

macht die Verwendung von && völlig überflüssig, und so gibt es kein Problem! Ich sehe, dass man sogar Folgendes tun kann:

if condition result_1 else result_2 end

In diesem Fall ist es wahrscheinlich einfacher, das Schlüsselwort end hinzuzufügen, als ein Makro zu erstellen. Aber danke, dass du dir trotzdem die Zeit genommen hast, es zu machen ^_^ Ist es eine gute Idee, die Möglichkeit zu einzeiligen if-Anweisungen in der Dokumentation hinzuzufügen? Ich sehe, dass, wenn man ?If<enter> macht, das Ergebnis schon ziemlich viele Zeilen sind... Aber ich finde, dass dieses Feature mehr beworben werden sollte.

In Bezug auf die ursprüngliche Diskussion bin ich dafür, "If x then y" hinzuzufügen, obwohl ich es mit der einzeiligen Version von "if" etwas überflüssig finde. Aber hey, schreiben Sie Code, wie es für Sie sinnvoll ist, oder?

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen

Verwandte Themen

TotalVerb picture TotalVerb  ·  3Kommentare

sbromberger picture sbromberger  ·  3Kommentare

StefanKarpinski picture StefanKarpinski  ·  3Kommentare

m-j-w picture m-j-w  ·  3Kommentare

StefanKarpinski picture StefanKarpinski  ·  3Kommentare