Darf ich {x, a, b} schreiben // Do [..., #] & statt Do [..., {x, a, b}]?

8

Ich bin in Ruby verliebt. In dieser Sprache sind alle Kernfunktionen tatsächlich Methoden. Deshalb bevorzuge ich Postfix-Notation - wenn die Daten, die ich verarbeiten möchte, links vom Körper der anonymen Verarbeitungsfunktion platziert werden, zum Beispiel: array.map{...} . Ich glaube, dass es Vorteile darin hat, wie einfach dieser Code zu lesen ist.

Aber Mathetica, funktional (ja, es kann prozedural sein, wenn Sie wollen) diktiert einen Stil, bei dem der Funktionsname links von den Daten steht. Wie wir in seinen Handbüchern sehen können, wird // nur verwendet, wenn es sich um eine einfache Funktion handelt, ohne Argumente wie list // MatrixForm . Wenn Function viele Argumente benötigt, verwenden Leute, die Handbücher geschrieben haben, die Syntax F[data] .
Es wäre okay, aber mein Problem ist der Fall F[f,data] , zum Beispiel Do[function, {x, a, b}] . Die meisten Mathematica-Funktionen (wenn nicht alle) haben Argumente in genau dieser Reihenfolge - [function, data] , nicht [data, function] . Da ich es vorziehe, reine Funktionen zu verwenden, um den Namespace sauber zu halten, anstatt viele benannte Funktionen in meinem Notizbuch zu erstellen, kann das Argument function zu groß sein - so groß, dass das Argument data in der 5-20. Zeile steht Code nach der Zeile mit Funktionsaufruf.

Das ist der Grund, warum manchmal, wenn böses Ruby-Natur mich unter Kontrolle bringt, ich solche Funktionen in Postfix-Weise umschreibe:

Weil es für mich wichtig ist, dass die reine Funktion (potentiell großer Code) direkt aus der Datenverarbeitung kommt. Ja, ich mache es und ich bin glücklich. Aber es gibt zwei Dinge:

  1. dies verursacht Mathematicas Hervorhebungsanalyse-Problem: Die x in Postfix-Notation ist mit blauer Farbe, nicht türkis hervorgehoben;
  2. Jedes Mal, wenn ich mir Mathematica-Handbücher anschaue, sehe ich Beispiele wie dieses: Do[x[[i]] = (v[[i]] - U[[i, i + 1 ;; n]].x[[i + 1 ;; n]])/ U[[i, i]], {i, n, 1, -1}]; , was bedeutet ... Hölle, sie denken, es ist einfach zu lesen / zu unterstützen / etc.?!

Diese zwei Dinge haben mich dazu gebracht, diese Frage hier zu stellen: Bin ich so ein böser Junge, der meinen Ruby-Stil benutzt, und sollte ich Code schreiben wie diese Jungs oder ist es OK, und ich muss mir keine Sorgen machen und sollte schreiben wie ich möchte?

    
Nakilon 17.08.2011, 15:38
quelle

6 Antworten

6

Mathematica unterstützt 4 Möglichkeiten, eine Funktion auf seine Argumente anzuwenden:

  1. Standardfunktionsform: f[x]
  2. Präfix: f@x oder g@@{x,y}
  3. postfix: x // f und
  4. infix: x~g~y entspricht g[x,y] .

Welche Form Sie wählen, hängt von Ihnen ab und ist oft eine ästhetische Wahl, mehr als alles andere. Intern wird f@x als f[x] interpretiert. Persönlich verwende ich Postfix wie Sie hauptsächlich, weil ich jede Funktion in der Kette als eine Transformation ansehe und es einfacher ist, mehrere Transformationen zusammen zu stringeln. Das heißt, mein Code wird sowohl mit der Standardform als auch mit der Präfixform übersät sein, je nach Laune, aber ich neige dazu, die Standardform mehr zu verwenden, da sie ein Gefühl der Eindämmung in Bezug auf die Funktionsparameter hervorruft.

Ich habe ein wenig Freiheit mit dem Präfix Formular genommen, da ich die Kurzform von Apply ( @@ ) neben Prefix ( @ ). Von den integrierten Befehlen können Sie mit nur dem Standardformular, dem Infixformular und Apply mühelos mehr als eine Variable ohne zusätzliche Arbeit an Ihre Funktion übergeben. Apply (zB g @@ {x,y} ) ersetzt das Head des Ausdrucks ( {x,y} ) mit der Funktion, wobei die Funktion mit mehreren Variablen ausgewertet wird ( g@@{x,y} == g[x,y] ).

Die Methode, mit der ich mehrere Variablen über das Postfix-Formular an meine Funktionen übergebe, geschieht über Listen. Dies erfordert ein wenig mehr Arbeit, da ich schreiben muss

%Vor%

um anzugeben, welches Element von List dem entsprechenden Parameter entspricht. Ich neige dazu, dies zu tun, aber Sie könnten dies mit Apply like

kombinieren %Vor%

was weniger Eingabe erfordert, aber schwieriger zu interpretieren sein könnte, wenn Sie es später lesen.

Bearbeiten : Ich sollte darauf hinweisen, dass f und g oben nur Platzhalter sind, sie können und werden oft durch reine Funktionen ersetzt, z. #+1& @ x entspricht meistens #+1&[x] , siehe Leonids Antwort .

Um zu klären, pro Leonids Antwort , die Äquivalenz zwischen f@expr und f[expr] ist wahr, wenn f kein Attribut , die verhindern würde, dass der Ausdruck expr ausgewertet wird, bevor er an f übergeben wird. Zum Beispiel ist eines der Attributes von Do HoldAll , das es erlaubt zu handeln als ein Scoping-Konstrukt, das erlaubt, dass seine Parameter intern ausgewertet werden, ohne Einfluss von außen rückgängig zu machen. Der Punkt ist expr wird ausgewertet, bevor es an f übergeben wird. Wenn Sie es also nicht evaluieren möchten, müssen Sie besonders vorsichtig sein, wie zum Beispiel eine reine Funktion mit einem Hold style Attribut .

    
rcollyer 17.08.2011, 16:11
quelle
10

Der von Ihnen vorgeschlagene Stil ist häufig möglich, wird jedoch im Fall von Do nicht empfohlen. Das Problem ist, dass Do das Attribut HoldAll hat. Dies ist wichtig, da die Schleifenvariable ( x im Beispiel) nicht ausgewertet werden und als lokale Variable behandelt werden muss. Versuchen Sie, diese Ausdrücke zu überprüfen:

%Vor%

Der Fehler tritt auf, weil die reine Funktion Do[Print[x], #]& das HoldAll -Attribut nicht enthält, wodurch {x, 1, 2} ausgewertet wird. Sie könnten das Problem lösen, indem Sie explizit eine reine Funktion mit dem Attribut HoldAll definieren, also:

%Vor%

... aber ich vermute, dass die Heilung schlimmer ist als die Krankheit:)

Wenn also "bindende" Ausdrücke wie Do , Table , Module usw. verwendet werden, ist es am sichersten, sich an die Herde anzupassen.

    
WReach 17.08.2011 16:25
quelle
8

Ich denke, Sie müssen lernen, die Stile zu verwenden, die Mathematica am meisten natürlich unterstützt. Sicher gibt es mehr als einen Weg, und mein Code sieht nicht wie jeder andere aus. Wenn Sie jedoch weiterhin versuchen, die Syntax von Mathematica in Ihren eigenen vorgefassten Stil zu bringen, der auf einer anderen Sprache basiert, sehe ich nichts als anhaltende Frustration für Sie.

Leerzeichen sind nicht böse, und Sie können Zeilenumbrüche hinzufügen, um lange Argumente zu trennen:

%Vor%

Das heißt, ich schreibe lieber mit mehr Präfix (% ​​co_de%) und Infix (% ​​co_de%) Notation, die ich normalerweise sehe, und ich finde das wertvoll, weil es einfach zu bestimmen ist, dass solche Funktionen eins und zwei erhalten Argumente jeweils. Dies ist etwas nicht standardgemäß, aber ich denke nicht, dass es die Spuren der Mathematica -Syntax übertritt. Ich sehe es vielmehr als Nutzen der Syntax. Manchmal führt dies dazu, dass die Syntaxhervorhebung fehlschlägt, aber ich kann damit leben:

%Vor%

Wenn Sie etwas außer der Standardform von f @ x (mit Zeilenumbrüchen nach Bedarf) verwenden, müssen Sie sorgfältiger auf die Auswertungsreihenfolge achten, und IMHO kann die Lesbarkeit leiden. Betrachten Sie dieses erfundene Beispiel:

%Vor%

Ich finde das nicht intuitiv. Ja, für jemanden, der mit der Operationsfolge von Mathematica intim ist, ist es lesbar, aber ich glaube, dass es die Klarheit nicht verbessert. Ich neige dazu, x ~ f ~ y postfix für benannte Funktionen zu reservieren, bei denen das Lesen natürlich ist:

%Vor%     
Mr.Wizard 17.08.2011 16:09
quelle
7

Ich würde sagen, dass es einer der größten Fehler ist, das Programm in einer Sprache B in einer Weise zu programmieren, die für eine Sprache A idiomatisch ist, nur weil Sie letztere gut kennen und mögen. Es ist nichts falsch daran, Idiome zu borgen, aber Sie müssen sicherstellen, dass Sie die zweite Sprache gut genug verstehen, so dass Sie wissen, warum andere Leute sie so verwenden, wie sie es tun.

Im besonderen Fall Ihres Beispiels und allgemein möchte ich auf einige Dinge aufmerksam machen, die andere nicht erwähnt haben. Erstens ist Do ein Scoping-Konstrukt, das dynamische Scoping verwendet, um seine Iteratorsymbole zu lokalisieren. Daher haben Sie:

%Vor%

Was für eine Überraschung, nicht wahr? Dies geschieht nicht, wenn Sie Do standardmäßig verwenden.

Beachten Sie, dass, obwohl diese Tatsache weitgehend ignoriert wird, f[#]&[arg] NICHT immer gleich f[arg] ist. Beispiel:

%Vor%

Dies wirkt sich nicht auf Ihr Beispiel aus, aber Ihre Verwendung ist den betroffenen Fällen nahe genug, da Sie die Bereiche bearbeiten.

    
Leonid Shifrin 17.08.2011 16:24
quelle
5

Sie können es sicherlich tun, wie Sie es offenbar wissen. Persönlich würde ich mir keine Gedanken darüber machen, wie die Handbücher Code schreiben und einfach so schreiben, wie ich es natürlich und einprägsam finde.

Allerdings habe ich bemerkt, dass ich normalerweise in bestimmte Muster verlaufe. Zum Beispiel, wenn ich nach einer Berechnung eine Liste erstelle und sie zufällig grafisch zeichne, um sicherzustellen, dass es das ist, was ich erwartet habe, mache ich es normalerweise

%Vor%

Wenn ich eine Liste habe, sagen wir lst , und ich konzentriere mich jetzt darauf, eine komplizierte Handlung zu erstellen, mache ich

%Vor%

Im Grunde ist alles, was nebensächlich ist und vielleicht nicht wichtig ist, um lesbar zu sein (ich muss nicht in der Lage sein, das erste ListPlot sofort zu parsen, da es nicht der Punkt dieses Codes ist), als Postfix zu enden. um den bereits geschriebenen komplizierten Code nicht zu stören. Umgekehrt tendiere ich dazu, komplizierten Code so zu schreiben, wie ich es am leichtesten später parsen kann, was in meinem Fall etwas wie

ist %Vor%

, obwohl es mehr Eingabe benötigt und, wenn man nicht das Workbench / Eclipse-Plugin verwendet, macht es mehr Arbeit, Code zu reorganisieren.

Ich nehme an, ich beantworte Ihre Frage mit "tue, was immer am bequemsten ist, wenn man die mögliche Lesbarkeit und den möglichen Komfortverlust wie Code-Hervorhebung, zusätzliche Arbeit zum Refactor-Code usw. berücksichtigt".

Natürlich gilt all das, wenn Sie als Einziger mit einem Code arbeiten; Wenn es andere gibt, ist das alles eine andere Frage.

Aber das ist nur eine Meinung. Ich bezweifle, dass irgendjemand mehr als das anbieten kann.

    
acl 17.08.2011 16:10
quelle
1

Für die Funktionen mit einem Argument sind (f@(arg)) , ((arg)//f) und f[arg] sogar im Sinne der Anwendung von Attributen von f vollständig äquivalent. Bei Funktionen mit mehreren Argumenten kann man f@Sequence[args] oder Sequence[args]//f mit demselben Effekt schreiben:

%Vor%

So scheint es, dass die Lösung für jeden, der Postfix-Notation mag, die Verwendung von Sequence :

ist %Vor%

Einige Probleme können möglicherweise bei Funktionen mit dem Attribut SequenceHold oder HoldAllComplete auftreten:

%Vor%     
Alexey Popkov 17.08.2011 18:12
quelle