Less.js: Parametrisierte Mixins als getrennte Regelsätze zulassen, um „Lambdas“ zu bilden

Erstellt am 4. Nov. 2014  ·  118Kommentare  ·  Quelle: less/less.js

Es scheint, dass LESS derzeit nur "reine" Regelsätze unterstützt, die als Mixin-Argumente weitergegeben oder als getrennte Regelsätze in Variablen gespeichert werden.

Ich schlage vor, diese Unterstützung zu erweitern, um parametrisierte Mixins zu integrieren, was LESS im Wesentlichen die Möglichkeit gibt, mit Lambdas zu arbeiten.

Z.B
Man könnte schreiben

.list {
  .forEach(foo bar baz, (<strong i="9">@item</strong>, @index) {
    <strong i="10">@i</strong> : (<strong i="11">@index</strong> + 1);
    > li:nth-child(@{i}):before {
      content : "@{item}";
    }
  });
}

wobei .forEach definiert ist als

.forEach(<strong i="16">@list</strong>, @lambda) {
  <strong i="17">@n</strong> : length(@list);

  .for(0)
  .for(@index) {}
  .for(@index) when (<strong i="18">@index</strong> < @n) {
    @lambda(extract(<strong i="19">@list</strong>, @index), @index);
    .for(<strong i="20">@index</strong> + 1);
  }
}

Die Lambda-Mixin-Unterstützung würde auch wiederkehrende Probleme mit Funktionsrückgabeargumenten und dem hässlichen Hack, bei dem Variablen in den übergeordneten Bereich „aufsteigen“, wenn diese Variablen in diesem übergeordneten Bereich noch nicht definiert sind, ordentlich lösen.

Die vorgeschlagene Praxis könnte darin bestehen, eine Programmierung im Fortsetzungsstil zu übernehmen; Übergeben von "Rückgabewerten" an ein Lambda-Mixin, um die Scope-Kette fortzusetzen. Diese Art von Mechanismus ist für Benutzer transparenter, weniger spröde, da Probleme mit potenziellen Kollisionen von Variablennamen vermieden werden, und passt einfach besser zu den allgemeinen Paradigmen der funktionalen Programmierung, auf denen die LESS-Syntax aufbaut.

[BEARBEITEN]
Nachdem ich mir gerade angesehen habe, wie getrennte Regelsätze und Aufrufe im AST implementiert werden, denke ich, dass sehr wenig passieren muss, damit dies funktioniert. Sogar auf der Parser-Seite scheint es ziemlich einfach zu sein, einfach einen optionalen Block von mixin.args vor blockRuleset in der detachedRuleset -Parser-Funktion zu parsen und die Argumente an tree.DetachedRuleset weiterzugeben tree.DetachedRuleset müssten natürlich um die Parameterauswertung von tree.mixin.Definition erweitert werden.)

feature request medium priority needs decision

Hilfreichster Kommentar

$@ funktioniert!? Ich hatte keine Ahnung! Ich dachte, es wäre nixed! Das macht mich so glücklich!

Ha, ja, ich habe es in Fehlerkorrekturen gesteckt, bevor ich 3.5 veröffentlicht habe. ^_^

Alle 118 Kommentare

der hässliche Hack, bei dem Variablen in den übergeordneten Geltungsbereich „aufsteigen“.

Nur für den Fall, dass dies kein hässlicher Hack ist, sondern eine gut definierte Spracheinrichtung.
(Ich komme auch nicht auf die Idee, "Up-Chain-Scope-Probleme" mit der "Down-Chain-Parameter-Pass-Funktion" zu lösen, diese scheinen nicht verwandt zu sein, oder? Aber gut, egal, die Funktion bleibt trotzdem nützlich davon sowieso)


Nun, so oder so ist die Idee selbst ziemlich selbsterklärend und das einzige Problem ist die mehrdeutige Syntax, beachten Sie:

<strong i="11">@a</strong>: {1: 1};      // OK, ruleset
<strong i="12">@b</strong>: (@a);        // OK, set <strong i="13">@b</strong> to <strong i="14">@a</strong>
<strong i="15">@c</strong>: (@a) (@b);   // OK, array/list
<strong i="16">@d</strong>: (@a) {2: 2}; // ?!, array or unnamed ruleset with one parameter?
// same goes if this to be used as a mixin arg

In anderen Sprachen mit einer solchen Einrichtung wird dieses Problem mit bestimmten Schlüsselwörtern/Operatoren gelöst, die einem solchen Lambda vorangestellt sind (z. B. [] in C++ oder nur function in JavaScript).

Nur für den Fall, dass dies kein hässlicher Hack ist, sondern eine gut definierte Spracheinrichtung.

Wenn ich erwähne, dass es sich um einen "Hack" handelt, meine ich ausdrücklich, dass es in das vorhandene Sprachdesign gehackt zu sein scheint (um Rückgabewerte als spätere Ergänzung zu erleichtern), und nicht etwas, über das im Voraus nachgedacht wurde. Ich meine nicht, dass der eigentliche Code von geringer Qualität ist. Tatsächlich; der LESS-Parser und AST sind recht gut gemacht. (Spitze des Hutes dafür.)

Die Tatsache, dass es gut definiert und ausgereift ist, macht es jedoch nicht weniger hässlich, wenn es verwendet wird. Es ist eine Sprachfunktion, die für die meisten der Intuition völlig widerspricht, da dies keine andere Mainstream-Sprache tut.

Das einzige Problem ist die mehrdeutige Syntax
In anderen Sprachen mit einer solchen Einrichtung wird dieses Problem mit einigen bestimmten Schlüsselwörtern/Operatoren gelöst, die einem solchen Lambda vorangestellt sind

Darf ich <strong i="12">@a</strong>: (@b) => { b : b } vorschlagen?
Es erinnert sowohl an die Lambda-Delegates von C# als auch an die Harmony-Pfeilnotation von JavaScript in ES6 für Funktionen mit beibehaltenem lexikalischen Gültigkeitsbereich. Vorausgesetzt, Sie setzen getrennte Regelsätze an den Kopf der Typen, die der Parser auf Ausdrücke anzuwenden versucht (was meiner Meinung nach bereits der Fall ist), sollte dies zu einer deterministischen Analyse ohne Mehrdeutigkeiten führen.

Und wenn Sie _wirklich_ eine Liste mit einem expliziten => -Symbol darin haben wollten, nun ja; es gibt immer ~"=>" als Notausstieg. (Es ist nicht so, dass Sie dieses Problem nicht bis zu einem gewissen Grad bereits mit calc() haben.)

anstatt etwas, worüber man sich im Vorfeld Gedanken gemacht hat.

(Obwohl wir schnell vom Thema abschweifen - Ja, es war nicht etwas, was in den früheren Less-Tagen gedacht war, aber heute bleibt es immer noch _der einzige_ Weg, etwas von etwas in Less "zurückzugeben" (da die "Funktion"-Einrichtung immer noch etwas vernachlässigt wird, obwohl das Ganze eigentlich nicht auf die Rückgabe von Variablen beschränkt ist.) Also bestehe ich darauf :) dass "Parent Scope Leak" nichts mit Lambdas zu tun hat, schließlich geben Lambdas überhaupt nichts zurück. Und der Rest ist eine andere Geschichte ohne Bezug).


<strong i="10">@a</strong>: (@b) => { b : b } - Ja, könnte so etwas sein (obwohl ich persönlich => nicht mag :)

Gemäß der Diskussion in #1943 und auch im Zusammenhang mit der Weitergabe von Mixins als Referenz (Ausgabe # ?) würde ich diese Syntax vorschlagen:

.mixin(@args) {
    box-shadow+: <strong i="6">@args</strong> black;
}
a {
    each(10px 10px, -20px -20px, .mixin);
}

...gleicht...

.mixin(@args) {
    box-shadow+: <strong i="10">@args</strong> black;
}
<strong i="11">@list</strong>: 10px 10px, -20px -20px;
a {
    each(<strong i="12">@list</strong>, .mixin);
}

...gleicht...

<strong i="16">@list</strong>: 10px 10px, -20px -20px;
a {
    each(<strong i="17">@list</strong>, (@args) {
      box-shadow+: <strong i="18">@args</strong> black;
    });
}

Es gibt jedoch keinen Grund, warum Sie nicht dasselbe Konstrukt für benutzerdefinierte Mixins verwenden können sollten: .for(<strong i="21">@list</strong>, .mixin); und mit den Listen-/Mixin-Parametern machen, was Sie wollen.

Um genau zu sein, ist dies eine Erweiterung von Mixins / Parametern und keine getrennten Regelsätze, und das Übergeben von Mixins als Referenz wurde an anderer Stelle besprochen (obwohl ich es mit einer kurzen Suche nicht finden konnte).

und das Übergeben von Mixins als Referenz wurde an anderer Stelle besprochen (obwohl ich es mit einer kurzen Suche nicht finden konnte).

Es wurde in https://github.com/less/less.js/issues/965#issuecomment -18462037 erwähnt und dann ausführlicher unter https://github.com/less/less.js/pull/1648#issuecomment besprochen -33859876 und folgende Kommentare.

Per separater Diskussion mit @plugin scheint dies nun ein idealer Kandidat zu sein, um zugunsten einer benutzerdefinierten Funktion über @plugin zu schließen.

Außerdem ist dies seltsamerweise relevant für #1505, das ich gerade kommentiert habe, weil wir demonstrieren, wie eine CSS-Liste an eine benutzerdefinierte Funktion übergeben wird.

Dies scheint jetzt ein idealer Kandidat zu sein, um zugunsten einer benutzerdefinierten Funktion über @plugin zu schließen

Beachten Sie, dass Sie derzeit weder Bezeichner wie .mixin an eine Funktion übergeben können (vom Parser nicht erlaubt) noch eine Funktion aufrufen können, ohne ihr Ergebnis irgendetwas zuzuweisen ... Also nein, im Moment ist es einfach unmöglich, solche each über ein Plugin zu implementieren.

Also, nein, im Moment ist es einfach unmöglich, dies jeweils über ein Plugin zu implementieren.

Oh. Verdammt. Gut .... wäre es nicht ein guter Kandidat, um mehr Flexibilität für Plugins hinzuzufügen? Was ich meine, ist, dass es sich um einen engen Anwendungsfall handelt, und ich denke, wir hatten über enge Anwendungsfälle als Kandidaten für benutzerdefinierte Plugins gesprochen. ODER optionale Core-Plugins (die noch nicht definiert sind).

Also, für mich, wenn das reinkommt, erweitert es entweder den Kern auf die eine oder andere Weise. Eine wäre spezifisch für diesen Anwendungsfall und eine würde Plugins erweitern, um Szenarien wie diesen Anwendungsfall zu unterstützen.

@Sieben-Phasen-max
Also, nein, im Moment ist es einfach unmöglich, dies jeweils über ein Plugin zu implementieren.

Oh ... da wäre ich mir nicht so sicher.

Oh ... da wäre ich mir nicht so sicher.

Ja, aber in Ihrem Beispiel scheinen Sie nur eine Teillösung mit dem Plugin zu machen und dann den anderen Teil in einem rekursiven Mixin zu machen. Meine Frage war im Grunde, ob ein Plugin dies tun könnte (aus einem meiner obigen Beispiele:

<strong i="8">@list</strong>: 10px 10px, -20px -20px;
a {
   <strong i="9">@plugin</strong> "awesome-list-functions-which-contains-each";
    each(<strong i="10">@list</strong>, (@args) {
      box-shadow+: <strong i="11">@args</strong> black;
    });
}

Basierend auf Ihrem Kern sieht es so aus, als ob Sie @seven-phases-max zustimmen. Nein?

es scheint, dass Sie mit dem Plugin nur eine Teillösung machen

Ich könnte das Schleifenkonstrukt genauso gut in die eigentliche Funktion einbauen. Ich habe mich dagegen entschieden, um zu veranschaulichen, dass Sie tatsächlich die volle Lambda-Delegat-Funktionalität haben können, indem Sie einfach Variablen in den Geltungsbereich des getrennten Regelsatzes binden.

In der Tat; Überprüfen Sie das gleiche Wesentliche noch einmal. Ich habe es gerade mit Unterstützung für benannte Variablen aktualisiert ...

Basierend auf Ihrem Kern sieht es so aus, als ob Sie @seven-phases-max zustimmen. Nein?

Das Argument war, dass Sie weder Bezeichner wie ein Mixin an eine Funktion übergeben (also Parameter an das als Lambda-Delegat dienende Mixin übergeben könnten) noch eine Funktion ausführen könnten, ohne ihre Ausgabe einer Variablen oder Eigenschaft zuzuweisen (was Sie daran hindert, sie zu verwenden ein Lambda erstellen, das CSS ausgeben kann).

In meinem Fall verwende ich die Funktion, um einen zweiten getrennten Regelsatz um das Original zu wickeln, der die 'Parameter' des Lambdas einfügt (eigentlich sehr ähnlich wie Definition.prototype.evalCall funktioniert, wenn Parameter an Mixins übergeben werden) und dann gebe ich das zurück umschlossener Regelsatz als Ergebnis.
Ein losgelöster Regelsatz _kann_ natürlich aufgerufen werden, um CSS auszugeben.

Diese Umhüllungsschicht löst beide Probleme.

@rjgotten

Oh ... da wäre ich mir nicht so sicher.

Was Sie dort zeigen, ist ein Mixin, das sich beispielsweise nicht von diesem unterscheidet (dort vereinfachen Sie einfach die Less-Schleife über eine lambda -Funktion), aber um fair zu sein, ist das Plugin dort irgendwie redundant, da wir ein Mixin schreiben können die identische Funktionalität ohne Plugin (wenn ich mich nicht irre, wird das Plugin dort nur verwendet, um Variablen des äußeren Bereichs zu verbieten).

Also nein, abbrechen:

Also, nein, im Moment ist es einfach unmöglich, dies jeweils über ein Plugin zu implementieren.

Sie müssen each als Funktion zeigen, nicht als Mixin ;) (ansonsten ist es die gleiche Diskussion wie nach https://github.com/less/less.js/issues/1943#issuecomment-72945408) .

Das Argument war, dass man weder Bezeichner wie ein Mixin an eine Funktion übergeben könne

Und du kannst es immer noch nicht. DR ist kein Mixin! :) (es kann zum Beispiel keine Parameter haben). Als Benutzer möchte ich zB, dass mein Code Lambda-Argumente mit den Namen @v und @i (oder was auch immer ich brauche) hat. Ich möchte nicht, dass die vordefinierten @item und @index vordefiniert sind

Als Benutzer möchte ich, dass mein Code Lambda-Argumente mit den Namen @v und @i (oder was auch immer ich brauche) hat. Ich möchte nicht, dass die vordefinierten @item und @index Bloatware! ;)

Haben Sie den Teil verpasst, in dem die Parameternamen benutzerdefinierte bindbar sind? In meinem Beispiel sind sie behoben, aber Sie _könnten_ sie als zusätzliches Argument an das Mixin übergeben lassen, das den Lambda-Regelsatz verarbeitet. Mit meinem Kern als Beispiel:

.each(<strong i="12">@list</strong>, <strong i="13">@params</strong>, @ruleset) {
  <strong i="14">@length</strong> : length(@list);
  .iterate(1);
  .iterate(@index) when (<strong i="15">@index</strong> =< length) {
    <strong i="16">@item</strong> : extract(<strong i="17">@list</strong>, @index);
    <strong i="18">@out</strong>  : lambda(<strong i="19">@item</strong>, <strong i="20">@index</strong>, <strong i="21">@params</strong>, @ruleset);
    @out();
    .iterate(@index+1);
  }
})

.each(foo bar baz, v i, {
  value-@{i} : @v;
});

Das ist jedoch nicht sehr DRY und belastet Mixins, die Callback-Semantik anbieten, um diese Art von Parameterkonfiguration einzurichten. Ein besserer Weg wäre, die Lambda-Funktion selbst in zwei Komponenten aufzuteilen:

  1. ein bind(@name-a, @name-b, ..., @ruleset) und
  2. ein pass(@bound-ruleset, @value-a, @value-b, ... )

An diesem Punkt hat ein Aufrufer die vollständige Kontrolle über die Parameternamen:

.each(foo bar baz, bind(v, i, {
  value-@{i} : @v;
});

und intern müsste sich das Mixin nicht um sie kümmern und einfach pass aufrufen und dann den resultierenden umschlossenen getrennten Regelsatz auswerten.

.each(<strong i="36">@list</strong>, @ruleset) {
  <strong i="37">@length</strong> : length(@list);
  .iterate(1);
  .iterate(@index) when (<strong i="38">@index</strong> =< length) {
    <strong i="39">@item</strong> : extract(<strong i="40">@list</strong>, @index);
    <strong i="41">@out</strong>  : pass(<strong i="42">@ruleset</strong>, <strong i="43">@item</strong>, @index);
    @out();
    .iterate(@index+1);
  }
})

Sicher; es ist immer noch kein _echtes_ natives Lambda, aber es kommt _schrecklich_ nahe, nicht wahr? ;-)


Natürlich ist das alles immer noch ein Hack, der hoffentlich irgendwann durch Unterstützung in der Muttersprache ersetzt wird. Aber bis dahin ist es ein nettes semantisch (und fast syntaktisch) kompatibles 'Polyfill'.

.each(foo bar baz, bind(v, i, { ...

Der Drei-Eltern-Overkill ist in diesem Zusammenhang zu magischeren Dingen fähig:

.each(foo bar baz, { .function(<strong i="9">@v</strong>, <strong i="10">@i</strong>, @l) {
    threesome: <strong i="11">@v</strong> at <strong i="12">@i</strong> of ~"[" <strong i="13">@l</strong> ~"]";
}});

( impl. ).

@Sieben-Phasen-max
Das war eigentlich das, was ich vor Plugin-Funktionen verwendet hatte, und wie Sie bereits in Ihrem Kern bemerkt haben: Es bricht bei überladenen Signaturen.

Sie _können_ dafür sorgen, dass es im einfachen Fall mit einer 'Catch-all'-Signatur funktioniert, die auf einem Restparameter basiert (so dass der .function -Aufruf immer eine übereinstimmende Signatur hat, unabhängig von den Parametern, die der Verbraucher hat geliefert).
Allerdings fängt es dann an, wirklich _reaaaaa------lly_ seltsame Sachen zu machen, wenn Sie anfangen, verschachtelte Aufrufstrukturen wie .each innerhalb eines .each zu verwenden. Die Verwendung des getrennten Regelsatzes umgeht dieses Problem direkt.

Wie auch immer, ich glaube, ich hatte gerade eine Offenbarung, dies mit einer schöneren Syntax einzurichten. Ich werde es ein bisschen mehr hacken und sehen, ob es funktioniert. ^_^

Allerdings fängt es dann an, wirklich, reaaaaa------ly seltsame Sachen zu machen, wenn Sie anfangen, verschachtelte Aufrufstrukturen zu verwenden, wie z. B. ein .each in einem .each . Die Verwendung des getrennten Regelsatzes umgeht dieses Problem direkt.

Ja, deshalb bleibe ich bei meinem DR-freien .for , nachdem DRs eingeführt wurden ... Es hat keine Probleme mit der Verschachtelung, erlaubt benutzerdefinierte @item -Namen und das einzige Problem, das es gibt, ist zu sehen, dass es nicht so ist Wird in einem Mixin verwendet, das in den globalen Bereich erweitert werden soll, ohne {} zu umgeben.

Damit; einige Nachrichten. Ich habe irgendwie herausgefunden, wie man eine Reduce-Operation zum Laufen bringt:

.test {
  <strong i="6">@list</strong> : 1 2 3;
  <strong i="7">@init</strong> : 0;
  <strong i="8">@step</strong> : { <strong i="9">@return</strong> : @previous-item + @item; }

  .reduce(<strong i="10">@list</strong>, <strong i="11">@init</strong>, <strong i="12">@step</strong>, {
    value : @result;
  });
}
.test {
  value: 6;
}

(Ja; ich habe eine @plugin -Funktion, die zuweisbare Rückgabewerte aus ausgewerteten Regelsätzen zieht ...)

(Ja; ich habe eine @plugin- Funktion, die zuweisbare Rückgabewerte aus ausgewerteten Regelsätzen zieht ...)

Nur um eine Idee zu teilen. Ich habe ein Plugin in der Entwicklung (aber ich habe leider keine Zeit, es bald fertigzustellen) , mit dem Sie native Less-Mixins als native Funktionen auf kanonische Weise verwenden können, z.

.function-foo(@x) {
    return: <strong i="11">@x</strong> * 5; 
}

usage {
    width: foo(100px); // -> 500px
}

Offensichtlich erfordert dies ein paar schmutzige Hacks innerhalb des Plugins (hauptsächlich im Zusammenhang damit, den richtigen Bereichskontext für das aufgerufene Mixin in seinem Funktions-Wrapper zu erhalten), da dies nicht wirklich etwas ist, was Plugins überhaupt tun sollten.

Aber der Punkt ist: Wahrscheinlich könnten Sie auch etwas in diese Richtung in Betracht ziehen? (um zu tiefe DR-Abhängigkeiten/Hacks loszuwerden). Wie ich jetzt sehe, ist die Methode, die Sie verwenden, um all diese Dinge zu machen, ziemlich kurvig, dh:

  • Machen Sie ein Mixin, um DR als Lambda zu akzeptieren.
  • Hilfsfunktion(en) erstellen, um DRs zu hacken, damit es hilft, das zu machen, was das Mixin machen muss.
  • erfinden Sie eine hackige Art, diese Mixins zu verwenden, wenn Sie mit den Standardvariablennamen nicht zufrieden sind (oder aus irgendeinem anderen Grund die Weitergabe-DRs-in-Syntax nicht gut passt).
  • usw.

Aber der Punkt ist: Wahrscheinlich könnten Sie auch etwas in diese Richtung in Betracht ziehen? (um zu tiefe DR-Abhängigkeiten/Hacks loszuwerden).

Es ist tatsächlich überraschend sauber, umso mehr jetzt, wo ich noch mehr von der Cruft geräumt habe. ;-)

Wie auch immer, würden Mixins Ihnen nicht ein paar Probleme bereiten, wenn sie als Lambdas verwendet werden? Eines, das mir auf Anhieb einfällt, ist, dass ein einzelner Mixin-Aufruf mit mehreren Definitionen übereinstimmen und somit zu mehreren Rückgabewerten führen kann. In welchem ​​Fall; welche nimmst du?

In welchem ​​Fall; welche nimmst du?

Genauso wie überall: LDW .

Ah, und nochmal für alle Fälle: https://github.com/seven-phases-max/less-plugin-lists (ich mache Last-Minute-Make-ups vor der Veröffentlichung). Dieses Ding ist streng orthogonal zu dem, was Sie erstellen (primitive Funktionen vs. Iteratoralgorithmen), aber es wäre interessant zu sehen, wie sich beide auf verschiedene Anwendungsfälle auswirken (insbesondere Schlüsselwert-Lookups).

Ich habe tatsächlich auch primitive Funktionen; sowohl für Listen als auch für Karten.
Meine Listenerweiterungen sind so ziemlich das, was Sie auch geschrieben haben.

Ich habe wieder gesehen, dass jemand eine Art natives each haben wollte, um einen Datensatz an ein Mixin zu übergeben - #2601.

Ich denke, es gibt noch Raum für die Möglichkeit von etwas Einheimischem.

Heute habe ich ein einfaches Mixin gemacht, um Rems auszugeben, wenn es von einem Browser unterstützt wird:

.rem-size(<strong i="9">@property</strong>, @size) {
    @{property}: @size;
    @{property}: unit(<strong i="10">@size</strong> / 10, rem);
}

Füge meine Elemente hinzu:

.widget {
  .rem-size(font-size, 14px);
  .rem-size(width, 50px);
  .rem-size(height, 50px);
  .rem-size(padding-top, 10px);
}

Nach einem Moment wurde mir klar, dass das leider etwas schlampig und nicht leicht lesbar war. Was ich wollte, war eher so etwas wie:

.widget {
  .rem-size({
    font-size: 14px;
    width: 50px;
    height: 50px;
    padding-top: 10px;
  });
}

Es fühlt sich für mich sofort selbsterklärender an, was die Eigentumswerte anbelangt, die ich transformiere. Natürlich ... gibt es nichts dergleichen in Less. Was ich wollte, ist etwas, das alle Property / Value-Paare in Mixin-Aufrufe für jeden erweitern würde.

Wenn Sie sich die Anzahl der damit verbundenen Anwendungsfälle / Probleme ansehen, denke ich, dass wir den Anschluss verpassen. Das Erweitern von Listen zu Mixins ist eine häufig nachgefragte Funktion. Es ist nur so, dass die Leute auf verschiedene Weise danach fragen.

Plugins können das vielleicht, aber ich bin mir jetzt nicht sicher, ob sie das unbedingt sollten. Ich denke, wir können uns in diesem Thread bisher darauf einigen, dass die Funktionalität benötigt wird, und wir müssen uns nur entscheiden

  • [ ] wenn wir zum Kern hinzufügen sollten,
  • [ ] was die Syntax sein sollte.

Ist das eine faire Aussage?

@matthew-dean pixrem ? Das Schreiben eines Postprozessor-Plugins zum Einfügen von Fallbacks für ein normal geschriebenes CSS wie font-size: 1rem; klingt vernünftiger (neben künstlicher Syntax hätte die Lambda/each/whatever-Konstruktion auch Probleme mit Eigenschaften wie background: linear-gradient(135deg, red, blue) 1rem/2rem repeat-y fixed 3rem 4rem; ).

Die abstrakte Umwandlungsfunktion/-konstruktion „Regelsatz in Array von Eigenschafts-/Wertpaaren“ (und zurück) klingt gut, aber dann geht es um Anwendungsfälle, um die tatsächliche Syntax/das tatsächliche Verhalten zu formen. Also hypothetisch, background: linear-gradient(135deg, red, blue) 1rem/2rem repeat-y fixed 3rem 4rem; -ähnliche Dinge nicht zählen, sondern Sachen wie padding: 1 2 3 4 zählen, wie würde .rem-size intern aussehen?

@sieben-phasen-max :
Abstrakte Konvertierungsfunktion/Konstruktion "Regelsatz für Eigenschaft/Wert-Paare-Array" (und zurück) klingt gut

Heh. Ich verwende tatsächlich einen Plug-in-Satz von Funktionen, um auf diese Weise Wörterbücher zu erstellen.

Funktioniert hervorragend für Dinge wie das Zuordnen von Serien von Schriftsymbolen mit automatisch inkrementierenden Zeichencodebereichen, da Sie die Auswertung des Regelsatzes (und aller darin enthaltenen Mixins; somit Schleifen bilden) auslösen können, bevor das ausgewertete Ergebnis in ein Wörterbuch von Schlüssel umgewandelt wird. Wertepaare.

z.B

@map-icons     : map-build(@ruleset-icons);
@ruleset-icons : {
  <strong i="11">@chevrons</strong> : "chevron-up", "chevron-right", "chevron-down", "chevron-left";
  <strong i="12">@arrows</strong>   : "arrow-up"  , "arrow-right"  , "arrow-down"  , "arrow-left";

  .make-iconrange(<strong i="13">@chevrons</strong>, "e800");
  .make-iconrange(<strong i="14">@arrows</strong>  , "e810");
}

.make-iconrange(<strong i="15">@names</strong>, @code) {
  .iterate(hex2dec(@code), length(@names));
  .iterate(<strong i="16">@start</strong>, @index) when (<strong i="17">@index</strong> > 1) { .iterate(<strong i="18">@start</strong>, <strong i="19">@index</strong> - 1); }
  .iterate(<strong i="20">@start</strong>, @index) when (<strong i="21">@index</strong> > 0) {
    <strong i="22">@name</strong>   : e(extract(<strong i="23">@names</strong>, @index));
    @{name} : dec2hex(<strong i="24">@start</strong> + <strong i="25">@index</strong> - 1);
  }
}

// [ ... ]

.icon:before {
  <strong i="26">@code</strong>   : map-extract("chevron-up");
  content : "\@{code}";
}

(Intern verwendet es einen völlig neuen Knotentyp, um die Schlüsselwertzuordnung als Objektliteral zu speichern, sodass Sie eine konstante Suche erhalten, anstatt ständig die gesamte Liste durchlaufen zu müssen, um einen Wert für einen bekannten Schlüssel zu extrahieren. Die Geschwindigkeit -up ist ziemlich dramatisch.)

@rjgotten

Heh. Ich verwende tatsächlich einen Plug-in-Satz von Funktionen, um auf diese Weise Wörterbücher zu erstellen.


Beachten Sie, dass dieser gesamte Code nur zum Emulieren von C-ähnlichen Aufzählungen verwendet wird, z.

enum {
    a,
    b = 33,
    c,
    d = 42,
    e,
    etc
};


Wenn ich versuchen würde, solchen Code über externe Plugin-Funktionen zu abstrahieren, würde ich etwas Ähnliches wie less-plugin-lists:at verwenden (mit nur leicht unterschiedlichem Verhalten), z. B. (zeigt keine Hex <-> Dez-Konvertierung):

<strong i="19">@icons</strong>:
    chevron-up #00e800, chevron-right, chevron-down, chevron-left,
    arrow-up   #00e800, arrow-right, arrow-down, arrow-left;

.icon(@name) {
    <strong i="20">@code</strong>: enum-value(chevron-down);
    content : "\@{code}";
}

.icon:before {
    .icon(chevron-down);
}


Und wenn Sie es vorziehen, dass eine solche Funktion mit DR (anstelle einer einfachen Liste) arbeitet, könnte es ähnlich sein:

<strong i="27">@icons</strong>: {
    chevron-up: #00e800; chevron-right; chevron-down; chevron-left;
    arrow-up:   #00e800; arrow-right; arrow-down; arrow-left;
};

(aber da es illegal ist, eine Eigenschaft/Variable ohne Wert auf diese Weise zu definieren, wird es ziemlich kniffliger, obwohl in einem einfachen Fall ein bisschen künstliche , / ; Verwechslung helfen sollte ).(Und übrigens, warum verwenden Sie all diese Anführungszeichen für Werte? CSS ist kein JavaScript! :P Die einzigen erforderlichen " in Ihrem Snippet sind im content .)


Dies hebt natürlich nicht die Nützlichkeit des Features für andere Anwendungsfälle auf.

Für diesen speziellen Fall sehen all diese DRs, entsprechenden .map-Mixins und Loops dort für mich ziemlich überarbeitet aus.

Wahr. Ich hätte sagen sollen, dass ich _derzeit_ eine Plugin-Funktion verwende, um Wörterbücher auf diese Weise zu erstellen. Mein Plan ist es, die Hex/Dez-Konvertierung für die Symbole irgendwann in eine dedizierte Funktion umzuschreiben und das letzte bisschen Unordnung mit dieser nativen Less-Schleife zu abstrahieren. Hatte bisher nur noch keine Zeit dazu.

Eines aber:
Die Tatsache, dass Sie eine _echte_ Karte/Wörterbuch erstellen können, die intern mit einer JS-Objektliteral-„Hash-Karte“ arbeitet, hat wirklich einen ziemlich großen praktischen Wert, wenn Sie mit Mengen von Hunderten von Elementen arbeiten müssen: eine Schleife durch eine Liste von -list via native Less wird in diesem Fall ziemlich langsam.

(Mein Beispiel war nicht ganz repräsentativ für diese Tatsache. In Wahrheit habe ich es mit Sätzen von über 100 Symbolen in benutzerdefinierten Symbolschriften zu tun, und ich fand schnell heraus, dass eine native Less-Schleife für Suchen nicht ausreicht.)

@seven-phases-max Ich habe das Gefühl, dass Sie sich beim Anwendungsfall / der Syntax aufgehängt haben, als ich nur sagte, dass ich einen sauberen Weg wollte, um eine Liste zu schreiben, die ich durchlaufen kann.

Mein grundlegender Punkt war: Viele Leute stoßen auf Szenarien mit Less, wo sie sind
a) eine Liste haben,
b) für jedes Mitglied der Liste ein Mixin ausführen möchte.

Ob mein spezielles Szenario mit einem Postprozessor durchgeführt werden kann / sollte, ist eher irrelevant und Ansichtssache.

(Obwohl zwei Meinungen dazu:
1) Less stellt kompiliertes CSS für PostCSS bereit, das dann wieder in ein AST konvertiert werden muss, daher ist PostCSS-basierte Verarbeitung ein ziemlich ineffizientes Muster, wenn ein Mixin es löst,
2) Selbst wenn es es löst, fügt es meinem Verarbeitungsstapel eine technische Belastung hinzu. Aber auch hier bin ich nicht wirklich an den Vorzügen von PostCSS interessiert, was diesen Thread betrifft.)

Während das Problem oben speziell nach Lambdas fragt, drehte sich die meiste Diskussion um die Syntax vom Typ "each", weil der ursprüngliche REASON @rjgotten Lambdas oder "parametrisierte Mixins als getrennte Regelsätze zum Bilden von Lambdas wollte" im ersten Beispiel: .forEach .

Also habe ich das einfach noch einmal aufgegriffen: Dies ist die Frage nach einem einheimischen each() . Und erneut die Frage zu stellen, was genau unser Konsens ist, ist mein Anwendungsfall nicht gültig.

Um diese Fragen etwas klarer zu formulieren:
1) Müssen Listen an Mixins gesendet werden, die mit jedem Mitglied der Liste arbeiten können? (Ich denke schon, weil es Teil unserer regulären Dokumentation ist.)
2) Gibt es genug Bedarf, dass eine native Funktion noch in Erwägung gezogen wird? Anstatt auf .-() when Hacks zurückzugreifen?
3) Wenn es nötig ist, wie könnte die Syntax lauten?

Ich bin nur neugierig, wo das steht und was die Meinungen auf dem Tisch sind.

@matthew-dean

b) Also habe ich das einfach noch einmal aufgegriffen: Dies ist die Frage nach einem nativen each() .

Aber Sie haben dies bereits unter https://github.com/less/less.js/issues/2270#issuecomment -72969605 getan.

Wenn Sie versuchen, eine Liste und eine Schleife für das rem/px-Polyfill zu verwenden, _werden_ Sie mit Code wie diesem enden (die Schleifensyntax spielt dort keine Rolle, das Problem liegt in den Schleifeninterna).

Schreiben eines Postprozessor-Plugins zum Einfügen von Fallbacks für ein normal geschriebenes CSS wie font-size: 1rem; klingt vernünftiger


ZB kann (und sollte) ein solches "rem polyfill" als "Post-Evaluation-Besucher" geschrieben werden, der direkt mit Less AST arbeitet (also überhaupt nichts mit PostCSS oder anderem externen Zeug zu tun hat).


Unabhängig von dieser rem polyfill-Bemerkung sehe ich nichts Falsches an einem nativen each (das sowohl mit einfachen Listen als auch mit Regelsätzen als Schlüssel/Wert-Arrays arbeitet). Beachten Sie jedoch, dass je mehr @rjgotten seine Bibliothek poliert, desto mehr bewegt er sich in eine andere Richtung: keine Schleifen und direktes Nachschlagen im Wörterbuch (was Less selbst mit seinen Regelsätzen nicht verwenden kann, es sei denn, sie enthalten _nur_ Variablen). Wir fangen also an, hier zwei recht orthogonale Merkmale zu haben.
(Eigentlich sogar drei: generische lambda (offensichtlich nicht unbedingt mit Schleifen zusammenhängend), each und eine key/value Struktur als Dictionary (zum direkten Nachschlagen) oder als Array (für Schleifen)).

Aber das hast du ja schon gemacht

Sicher, ok, vielleicht war mein Kommentar zu lang und ich hätte einfach sagen sollen: "Das ist mir heute wieder in den Sinn gekommen; wo stehen wir damit?" Soweit ich das beurteilen konnte, waren wir uns nicht annähernd einig. Entschuldigung, wenn das verwirrend war.

Ein Teil der für diesen Kommentar relevanten Diskussion ist die Frage der Übergabe von Selektoren als Referenz. @seven-phases-max Sie haben tatsächlich in #1848 erwähnt, dass diese Diskussion über die Bezugnahme auf ${} für dieses Thema relevant war.

Es könnte also sehr gut sein:

each(a b c; ${.mixin} );

oder

each(a b c; ${#namespace.mixin} );

Vielleicht müssen #1848 & #2433 zuerst implementiert werden?

Ja, ich nehme an, diese Dinge werden zusammen nützlich sein (und sollten sich daher beim Entwerfen gegenseitig berücksichtigen), aber es gibt keine direkte Abhängigkeit. ZB ist each(a b c; ${.mixin} ); cool (für komplexe Dinge), aber es bietet einen Mechanismus für einen einfach zu verwendenden Inline-Loop-Body .

Du meinst, stattdessen einfach ein Lambda verwenden?

Hoppla. Es ist nur ein Tippfehler. Ich meine "aber es bietet _kein_ Mechanismus für einen einfach zu verwendenden Inline-Loop-Körper".
Mit anderen Worten, idealerweise sollte es immer noch eine Möglichkeit geben, den gesamten erforderlichen Code in each selbst zu schreiben, wie in:

each(<strong i="8">@list</strong>, (@value) {
    box-shadow+: <strong i="9">@value</strong> black;
});

oder (nur versuchen, aus der JS-ähnlichen Syntax herauszukommen):

each(@list): (@value) {
    box-shadow+: <strong i="13">@value</strong> black;
}
// ^ this one won't be compatible with external DR or mixins of course :(

oder so...

Ja, wenn wir anonyme Mixins zulassen würden, wären sie meiner Meinung nach mit allem austauschbar, was wir als Mixin-Referenz verwenden. Also, ja, ich denke, Ihr erstes Beispiel ist legitim und kompatibel.

Dein Aufgabenbeispiel ist interessant. Ich mag die Idee von etwas Saubererem.

Ich habe mich auch gefragt, ob es eine Möglichkeit gibt, es umzudrehen, um das Mixin-Referenzproblem zu umgehen. Das heißt, eine Möglichkeit, die Liste an das Mixin zu übergeben, anstatt das Mixin und die Liste an jedes zu übergeben, wie:

.mixin[@list];  // Different syntax to evaluate each member of the list?
// or
.mixin each @list;   //better

Dann ist es auch mit Lambdas noch etwas sauberer:

(@value) {
    box-shadow+: <strong i="11">@value</strong> black;
} each @list;

// or maybe better as:

(<strong i="12">@index</strong>, @value) each <strong i="13">@list</strong> {
    box-shadow+: <strong i="14">@value</strong> black;
} 

Und möglicherweise:

.mixin each <strong i="18">@list</strong> when (length(@list) = 1);

Was halten Sie davon?

Wie auch immer, ich denke, Sie haben es richtig getroffen, dass mein ursprünglicher Vorschlag zu JavaScript-y ist. Ich mag diese eher "deklarative Erweiterung" -Idee.

Obwohl dies wahrscheinlich eine geringfügige Syntaxanpassung erfordert, um Listen als Listen statt als Variablen übergeben zu können:

<strong i="6">@list</strong>: a b c;
.mixin each (@list);
.mixin each (d e f);

//with mixin definition
.mixin(@letter) {
  property: @letter;
}

Wie auch immer, ich denke, Sie haben es richtig getroffen, dass mein ursprünglicher Vorschlag zu JavaScript-y ist.

Es ist nicht wirklich "JavaScript-y", sicher ist es nur eine natürliche Fortsetzung des Mixin-Aufrufs mit DR-Argument-Syntax, die wir bereits haben: .mixin(arg1, {/* stuff */}); , dh es sind nur Klammern und Klammern ähnlicher Spracheinheiten, die zusammen in a geformt werden ähnliche Weise für eine ähnliche Konstruktion :)


Apropos alt. Syntax, in der Tat, Ihre jüngsten Beispiele haben mich tatsächlich an einen Gedanken erinnert, zu dem ich immer komme, wenn ich mich mit komplexen Listen/Schleifen und ähnlichen Dingen befasse. „Es wäre viel einfacher und sauberer, wenn Funktionen und arithmetische Operationen ‚vektorisiert‘ gestartet werden könnten.“ Dh anstatt aufgebläht zu schreiben:

<strong i="11">@x</strong>: 3rem;
padding: 1 * <strong i="12">@x</strong> 2 * <strong i="13">@x</strong> 3 * <strong i="14">@x</strong> 4 * @x;

man könnte nur tun (Pseudo-Syntax):

padding: (1 2 3 4) * @x;

und so weiter (einschließlich vector op vector -> vector Sachen).

Auf die gleiche Weise könnten Funktionen (anstatt zu versuchen, Listenargumente selbst zu behandeln, wo dies nicht erforderlich ist) auch einen "vektorisierten" Aufrufmodus haben, z.

@base-colors: red green blue black;
@light-colors: <some vector call mark>:::lighten(@base-colors, 15%); // same unknown pseudo syntax

@another-list: 10 20 30 40;
@more-light-colors: <some vector call mark>:::lighten(@base-colors, @another-list * 1%);

Jetzt, in der Tat, als Sie es erwähnt haben, ist mir klar, dass dasselbe (noch keine Ahnung von Syntax), wenn es auf Mixins angewendet wird, auch nichts anderes als nur eine each Konstruktion ist ...
Seltsamerweise nehme ich an, dass es relativ einfach zu implementieren wäre, aber die Syntax selbst könnte ein Problem beim Erstellen sein (ehrlich gesagt kann ich noch nichts Nützliches erfinden). Neben der Angabe, dass vector/each sich selbst markiert, sollte es idealerweise auch die Kontrolle darüber bieten, für welche arg und arg _s _ ein Mixin/Funktionsaufruf "vektorisiert" werden soll.

Bei einem gegebenen .mixin(a1, a2, ..., an) {...} (oder einer Funktion mit mehreren Argumenten) gibt es beispielsweise mehrere Varianten für "jedes" (vorausgesetzt, wir wollen das Mixin selbst nicht einschränken und die Konstruktion selbst für a nur in Einzelfällen):

  1. Rufen .mixin für jeden a1 Artikel auf ( a2 wird unverändert übergeben)
  2. rufen .mixin für jedes a2 Element auf ( a1 wird unverändert übergeben)
  3. rufen .mixin für jeden a1 und a2 Artikel an (wie in .mixin(a1[i], a2[i] )
    usw. usw.

Mit anderen Worten, (der Einfachheit halber werden nur explizit definierte Mixins verwendet, ohne dass der Iterationskörper "inplace" noch berücksichtigt wird), mit einer Pseudo-Syntax wird es so etwas wie:

each(<multiple args>) mixin(<normal-arg or a place-holder for one of "each" arg items>)...

// i.e.

<strong i="48">@a</strong>: 1 2 3 4;
<strong i="49">@b</strong>: 42;
<strong i="50">@c</strong>: 5 6 7 8;

each(@a) mixin(<each-arg-1-place-holder>, <strong i="51">@b</strong>, ...)
each(@a) mixin(<strong i="52">@b</strong>, <each-arg-1-place-holder>, ...)
each(@a) mixin(<each-arg-1-place-holder>, <each-arg-1-place-holder>, ...)
each(<strong i="53">@a</strong>, @c) mixin(<each-arg-1-place-holder>, <each-arg-2-place-holder>, ...)
each(<strong i="54">@a</strong>, @c) mixin(<each-arg-2-place-holder>, <each-arg-1-place-holder>, ...)
// etc. etc.

Außerdem sollten natürlich dieselben Platzhalter für den aktuellen Index vorhanden sein (um bedingte Dinge darin zu behandeln). Usw.


Nun, ich denke, Sie sehen die Idee bereits.
(Mir ist klar, dass das alles extrem kompliziert aussehen mag, da ich versuche, die ganze Geschichte auf einmal abzudecken, aber im Allgemeinen glaube ich, dass dies jedes andere Iterationssystem schlagen kann, vorausgesetzt, man könnte eine saubere Syntax mit "you don't" erfinden Wenn möglich, müssen Sie dort keine Dinge angeben, die Sie nicht verwenden. Nun, ich werde weiter darüber nachdenken, ob ich das besser (re)präsentieren könnte).

Bei einem .mixin(a1, a2, ..., an) {...} (oder einer Funktion mit mehreren Argumenten) gibt es beispielsweise mehrere Varianten für "jedes" (vorausgesetzt, wir möchten keine einfügen Beschränkung auf das Mixin selbst und die Konstruktion selbst nur für bestimmte Fälle fest codieren):

Ich denke, dass wir der Einfachheit halber nur die Weitergabe einer einzelnen Liste an ein einzelnes Mixin unterstützen möchten. Ich denke, ich habe angedeutet, dass, wenn Ihre Liste eine Liste von Listen wäre, jedes innere Listenmitglied als einzelne Argumente übergeben würde. Theoretisch könnten wir aber beides machen, über Mixinarity Matching.

.mixin(@list) { }
.mixin(@a; @b; @c) { }

<strong i="8">@nested</strong>: 1 2 3, 4 5 6, 7 8 9;
.mixin each (@nested);   // or each(@nested)::mixin();  or whatever

Wenn Sie ein Mixin definieren, das mit einem Parameter übereinstimmt, ruft es jedes Mixin auf, das mit einem Parameter übereinstimmt, und übergibt die Liste. Wenn Sie ein passendes Mixin mit der richtigen Anzahl von Argumenten für die innere Liste haben, könnte es mit diesem Mixin übereinstimmen.

Ich weiß nicht, ob wir das als Wächter haben (glaubst du nicht?), aber du könntest tun:

.mixin(@list) when (islist(@list)) { }

... für den Fall, dass Sie Fälle von Mixin, die für Listenmitglieder aufgerufen wurden, von denen, die für Listenmitglieder aufgerufen wurden, trennen mussten.

Außerdem denke ich, dass @index im Fall der Iteration als magische Variable (wie @arguments) angezeigt werden sollte, anstatt es in der Mixin-Definition selbst definieren zu müssen (was mühsam ist). So dass Sie Folgendes tun könnten:

.mixin(@x) when (<strong i="18">@index</strong> = 0) { 
  // add stuff for the first call
}

Ich mag deine Vektorsachen, aber die Syntax ist wahrscheinlich etwas zu dünn / mehrdeutig. (Klammern werden bereits mit einer regulären mathematischen Anweisung / Mixin / Function / etc verwendet.) Ich mag auch die Idee einer "Directing" - oder "Assignment" -Syntax von each to mixin. Auch ich hatte versucht, mir etwas einfallen zu lassen oder an irgendetwas CSS-y zu denken, aber stattdessen ging ich mit etwas WENIGER-y.

Gute Arbeit!

Ich beschloss, dies mit vorhandener Syntax und Strukturen anzugehen, dh eine Liste und einen Regelsatz an eine Funktion zu übergeben und den Regelsatz basierend auf den Mitgliedern der Liste umzuwandeln.

Schauen Sie sich die zugehörigen PRs an.

@matthew-dean Mm ... Hier ist eine nahezu äquivalente Implementierung (nicht optimiert, ohne Fehlerbehandlung) _ohne_ dass Änderungen im Kern erforderlich sind. Der einzige Unterschied besteht darin, dass anstelle von each .each wird.

Das heißt, ich hoffe, Sie erkennen, dass Ihre Implementierung, da sie zwei ziemlich große Kernänderungen erfordert, in absehbarer Zeit nicht akzeptiert wird. Zuerst müssen wir es bis zum Tod besprechen. (Die Menge der zu analysierenden Dinge und die Menge der zu schreibenden Tests sind ein bisschen beängstigend).

PS So oder so :+1:

Nun, Plugins kamen zuerst. Ich fing an, etwas zu tun, irgendetwas Nützliches in Bezug auf die Verwendung mit einem Framework, und nur einen Eigenschaftswert zurückgeben zu können, ist von so begrenztem Wert, dass es sich nicht lohnt.

Aber wenn Funktionen wie Mixins in jeder Knotentiefe expandieren können, öffnet das alles. Funktionen geben nach wie vor wirklich nur einen einzelnen Knoten zurück, aber die Beschränkung auf den Knotentyp wird einfach aufgehoben.

Die each() -Implementierung war danach im Grunde ein nachträglicher Einfall. Mir wurde klar, dass, sobald Sie eine Funktion definieren könnten, um sie in einen beliebigen Knotentyp zu erweitern, und diese Funktion jeden anderen Knotentyp erhalten könnte, nun, dann wird die ganze Sache sehr einfach. Ich wollte auch die vorhandene API testen.

Ich weiß, es ist eine große Veränderung. each() ist mir egal, ob sein Kern, abgesehen von Loop-Hacks, etwas üblich ist. Es könnte aber auch der gezeigte Proof of Concept für @plugin sein. (Vielleicht eines der wenigen "Kern"-Plugins.) Beide Wege haben eine gewisse Gültigkeit.

Was die Funktionsänderungen an sich betrifft, würde ich gerne weitere PRs erstellen, die die API erheblich vereinfachen, und dann würde ich gerne die Verantwortung übernehmen, die API umfassend zu dokumentieren und weniger Dokumente zu aktualisieren, wenn diese vorankommen können. Nachdem ich mit den Baumknoten gearbeitet habe, denke ich, dass sie derzeit viel zu kompliziert und umständlich sind, um es wert zu sein, dokumentiert zu werden. Aber ich habe Ideen, wie ich das beheben kann.

Aber wenn Funktionen wie Mixins in jeder Knotentiefe expandieren können, öffnet das alles. Funktionen geben nach wie vor wirklich nur einen einzelnen Knoten zurück, aber die Beschränkung auf den Knotentyp wird einfach aufgehoben.

Die each() -Implementierung war danach im Grunde ein nachträglicher Einfall.

:+1:

each() ist ein sehr nettes _Showcase_ der erweiterten Anwendbarkeit von Funktionen in der Grammatik, aber es ist die erweiterte Grammatik, die das wahre Killer-Feature ist.

@rjgotten Richtig? Ich habe damit gespielt, coole Dinge zu tun, wie zum Beispiel einen losgelösten Regelsatz mit einer Funktion an eine Variable zurückzugeben und sie dann aufzurufen. Sie könnten also potenziell einzigartige Transformationen an DRs durchführen (was in der Art von each() der Fall ist), und Sie haben im Grunde eine Leistung auf PostCSS-Ebene, außer dass Less-Plugins von Natur aus besser mit anderen spielen und einfacher zu installieren sind (weil Sie müssen sie überhaupt nicht installieren, bevor Sie den less-Compiler aufrufen).

Ich würde es wirklich lieben, wenn die @plugin- PR von allen überprüft würde, damit sie nicht ewig sitzen bleiben muss.

Ich würde es wirklich lieben, wenn die PR von @plugin von allen überprüft würde,

Meinst du #2785?
Wenn dem so ist, ist es wirklich _nur_ die Funktion „Root Functions“ (oder „Allow Non-Value Functions“, da „Root“ verwirrend ist), da es in keiner Weise auf Plugins eines beliebigen Formats beschränkt ist (oder beschränkt werden sollte). Ich habe mir den Code kurz angesehen und nichts falsches gesehen. Es ist nur die Fehlerbehandlung, die aufpoliert werden muss (hmm, ich denke, ich könnte eine PR an den Zweig für vorgeschlagene Änderungen machen)).

PS Kann eine Funktion ein Array von Regeln zurückgeben? (Inzwischen scheint das Erstellen von & Regelsatz- oder DR-Call-Emulation zur Rückgabe eines solchen Arrays begrenzt zu sein. Was ist, wenn ich eine Liste von Variablendefinitionen zurückgeben möchte? :) Obwohl ich annehme, dass dies später verbessert werden könnte.

Ja, #2785. Der Grund, warum @plugin das Thema war, ist, dass ich nicht darüber nachgedacht hatte, was es für Kernfunktionen bedeuten könnte. Also dachte ich damals nur an benutzerdefinierte Funktionen.

2786 basierte auf #2785, da Sie sonst keine Root-Funktion wie each() ausführen könnten. Ich wusste keinen besseren Git-Weg, aber im Grunde würde #2786 viel kleiner aussehen, wenn #2785 drin wäre. Es ist wirklich nur dieses Commit: https://github.com/less/less.js/commit/f52b0736015d69f01e9be3257b039f2f332a613f

@seven-phases-max Hoffentlich hast du bemerkt, dass ich einen Testfall deines Szenarios "Vektormathematik" als Geschenk für dich gemacht habe, lol. Ich mache gerne andere Testfälle oder Fehlerbereinigungen für #2785, weil ich mich auf diesen hier freue.

Habe übrigens gerade deine Implementierung angeschaut. Peinlich, dass ich mir das nicht früher angesehen habe, oder vielleicht versprechend, dass die Implementierungen so ähnlich sind? Mir gefällt, dass Sie value anstelle von item verwendet haben. Das ist wahrscheinlich besser. Ich mochte zwei Vars nicht wirklich, die mit "I" begannen. Ihre Implementierung ist großartig, aber sie sorgt immer noch für viel überschüssigen Code ohne Root-Funktionen. Ansonsten ist unser Code verdammt nah dran.

Ein Grund, warum ich anfing, mich eher mit Funktionen als mit einem benutzerdefinierten Mixin zu beschäftigen, ist, dass es eigentlich nur logisch ist, dass es eine each() -Funktion oder ein Mixin gibt. Bei Funktionen ist das konstruktionsbedingt so, also ist es eine logische Übereinstimmung. Und da Ihr Mixin eine Funktion aufruft, die einen Wert an eine Variable an eine Regelsatzauswertung übergibt, "verschieben" all diese Schritte einfach das Funktionsergebnis an die Wurzel des Regelsatzes. Das beabsichtigte Ergebnis ist, dass Ihre Funktion an der Wurzel ausgewertet wird.

oder vielleicht vielversprechend, dass die Implementierungen so ähnlich sind?

Es liegt nur daran, dass ich Ihnen den Code buchstäblich gestohlen habe :) (Ich habe nur ein paar Dinge überarbeitet, damit die zurückgegebenen Regeln eine DR-ähnliche Sichtbarkeit behalten).

Ich finde es gut, dass Sie eher Wert als Gegenstand verwendet haben. Das ist wahrscheinlich besser.

In der finalen Version soll es natürlich auch [value index] statt [index value] heißen.


Im Allgemeinen ist meine Implementierung nur eine Demo-Umgehung für das Problem „keine Root-Funktionen“ (sowie keine direkte Weitergabe von DR-Werten), mehr nicht. Schließlich (im Kontext dieses Threads) wird nur enthüllt, dass das frühere :

Sie können auch keine Funktion aufrufen, ohne ihr Ergebnis etwas zuzuweisen ...

kann doch getäuscht werden (obwohl noch andere Einschränkungen gelten, so dass es noch nicht _dass_ each ist, aber es ist tatsächlich ziemlich nah dran).


Aber sobald es weiter geht als dieser spezielle Thread, ist "Allow Non-Value Functions" zweifellos der richtige Weg. Sowie "Improved Func Arguments Syntax" (um ehrlich zu sein, sind mir diese ; dort egal, weil ich sowieso bei each(a b c, value index, {...}); bleiben werde, aber DRs müssen statt dessen passabel sein natürlich, damit das Ganze funktioniert).

Oh haha, ich dachte, Sie sagten, Sie hätten es schon einmal implementiert.

Ja, das Semikolon bietet die gleiche Option wie das, was für Mixins verwendet wird, also ist es keine Belastung für den Support. Tatsächlich habe ich den Funktionsargumentcode durch eine modifizierte Version des Mixin-Argumentcodes ersetzt, obwohl ich glaube, dass ich "Zuweisung" hinzugefügt habe.

Folgen Sie den obigen " each() via Plugin" Sachen. Ich bin auf eine neue (Plugin-basierte) Implementierungsmethode gestoßen, die auf praktisch _jede_ for/for-each/each -Syntax angewendet werden kann, die den Parser passieren kann.
Insbesondere durch den Missbrauch von #2824 ist derzeit die folgende Syntax möglich (siehe den schnellen Prototypen ):

<strong i="10">@list</strong>: a b c, e f g;

usage {
    .for-each(<strong i="11">@x</strong> in @list) {
        .for-each(<strong i="12">@y</strong> in @x) { 
            r: <strong i="13">@y</strong> of ~"[@{x}]";
        }
    }
}

Genauso kann stattdessen praktisch jede andere geeignete Syntax verwendet werden, z.

.for(<strong i="17">@value</strong>, in, @list)  {...} // mixin def. not abusing #2824
.for(<strong i="18">@i</strong>: 0, <strong i="19">@n</strong>: 6)       {...}
.for(any thing)          {...} // not abusing #2824 as long as no @
<strong i="20">@for</strong> (any thing)         {...}
.for(<strong i="21">@value</strong> in <strong i="22">@list</strong>,    {...});
:for(i 1:6)              {...}
:for(value in list)      {...}
 for [value] in [list]   {...}
 for {<strong i="23">@value</strong>: in @list; -{...}}
// etc. and so on

(Eine Komplexität des Evaluierungscodes kann jedoch stark variieren).

@Sieben-Phasen-max
Das ist zu gleichen Teilen großartig und erschreckend ...

@rjgotten @seven-phases-max Einverstanden. Obwohl vielleicht 60% erschreckend.

Ich habe diesen faszinierenden Thread gefunden, als ich irgendwie das Gefühl hatte, dass ich Closures in CSS bräuchte 😄

Im Moment habe ich dieses Mixin zum Generieren von responsiven Präfixversionen verschiedener Dienstprogramme:

.responsive(@ruleset) {
    & { <strong i="7">@prefix</strong>: ~""; @ruleset(); }
    <strong i="8">@media</strong> (min-width: @screen-sm) { <strong i="9">@prefix</strong>: ~"sm-"; @ruleset(); }
    <strong i="10">@media</strong> (min-width: @screen-md) { <strong i="11">@prefix</strong>: ~"md-"; @ruleset(); }
    <strong i="12">@media</strong> (min-width: @screen-lg) { <strong i="13">@prefix</strong>: ~"lg-"; @ruleset(); }
    <strong i="14">@media</strong> (min-width: @screen-xl) { <strong i="15">@prefix</strong>: ~"xl-"; @ruleset(); }
}

Verwendet wie:

.responsive({
    .@{prefix}block { display: block;}
    .@{prefix}inline-block { display: inline-block;}
    .@{prefix}hidden { display: none;}
});

Funktioniert gut, aber ich wünschte, die Variable @prefix könnte irgendwie ein Parameter für den Regelsatz sein, anstatt sie unmittelbar vor dem Aufrufen des Regelsatzes definieren zu müssen und dem Regelsatz den Namen mitzuteilen.

Ich würde gerne in der Lage sein, alle oben genannten Dinge wie folgt umzuschreiben:

.responsive(@ruleset) {
    & { @ruleset(~""); }
    <strong i="24">@media</strong> (min-width: @screen-sm) { @ruleset(~"sm-"); }
    <strong i="25">@media</strong> (min-width: @screen-md) { @ruleset(~"md-"); }
    <strong i="26">@media</strong> (min-width: @screen-lg) { @ruleset(~"lg-"); }
    <strong i="27">@media</strong> (min-width: @screen-xl) { @ruleset(~"xl-"); }
}

.responsive((@prefix) {
    .@{prefix}block { display: block;}
    .@{prefix}inline-block { display: inline-block;}
    .@{prefix}hidden { display: none;}
});

Ist das die Art von Dingen, die die in diesem Thread vorgestellten Ideen ermöglichen könnten?

Übrigens. Ich habe gelegentlich die Idee einer möglichen Mehrdeutigkeitssyntaxauflösung (um https://github.com/less/less.js/issues/2270#issuecomment-61634539 zu beantworten). Wir könnten einfach ein Symbol direkt vor die Parameterliste setzen, z.

<strong i="6">@var</strong>: @(parameters...) {...body...};
.call(@(parameters...) {...body...});

(Ich habe kürzlich etwas Matlab-Code geschrieben und – Boom – festgestellt, dass sie genau das für anonyme Funktionen verwenden). Offensichtlich muss es nicht das Symbol @ sein (könnte . , ? usw. sein, aber keine arithmetischen oder relationalen Operatoren), und dann ist es nur das Symbol *( "Token", das eindeutig den Beginn der gesamten Konstruktion bezeichnet (ich glaube, es wird viel einfacher und übrigens schneller für den Parser und die Augen sein. Und ja, ich mag das JS nicht => Syntax).

Übrigens, @adamwathan , Sie wissen, dass Ihr aktueller Code fehlschlagen wird, wenn Sie gelegentlich eine globale @prefix -Variable haben, oder ?

Hey @seven-phases-max!

Übrigens, @adamwathan , Sie wissen, dass Ihr aktueller Code fehlschlagen wird, wenn Sie gelegentlich eine globale @prefix -Variable haben, oder?

Insgesamt ist dies ein wichtiger Grund, warum ich mir wünschte, ich könnte einen getrennten Regelsatz definieren, der Parameter akzeptiert, damit alle benötigten Daten richtig erfasst werden können.

Können Sie sich eine alternative Möglichkeit vorstellen, dieses Generator-Mixin zu schreiben und zu verwenden, bei der dieses Problem nicht auftritt?

.responsive(@ruleset) {
    & { <strong i="12">@prefix</strong>: ; @ruleset(); }
    <strong i="13">@media</strong> (min-width: @screen-sm) { <strong i="14">@prefix</strong>: sm-; @ruleset(); }
    <strong i="15">@media</strong> (min-width: @screen-md) { <strong i="16">@prefix</strong>: md-; @ruleset(); }
    <strong i="17">@media</strong> (min-width: @screen-lg) { <strong i="18">@prefix</strong>: lg-; @ruleset(); }
    <strong i="19">@media</strong> (min-width: @screen-xl) { <strong i="20">@prefix</strong>: xl-; @ruleset(); }
}

.responsive({
    .@{prefix}block { display: block;}
});

alternativer Weg

Es hängt davon ab, wie Sie diesen "Parameter" verwenden. In einem einfachen Fall wie oben benötigen Sie beispielsweise überhaupt keinen Parameter [1] :

.responsive(@ruleset) {
    @ruleset();
    <strong i="10">@media</strong> (min-width: sm) {sm-{@ruleset();}}
    <strong i="11">@media</strong> (min-width: md) {md-{@ruleset();}}
}

.responsive({
    &block {display: block}
});

Die Extreme der anderen Seite wären:
[2] "the triple parens"-Methode, zB:

.responsive(@rules) {
    & {@rules(); .-(~'')}
    <strong i="18">@media</strong> (min-width: sm) {@rules(); .-(sm-)}
    <strong i="19">@media</strong> (min-width: md) {@rules(); .-(md-)}
}

.responsive({.-(@prefix) {
    @{prefix}block {display: block}
}});

und "up-side-down", zB [3] :

.apply-responsive() {
    .responsive(~'');
    <strong i="25">@media</strong> (min-width: sm) {.responsive(sm-)}
    <strong i="26">@media</strong> (min-width: md) {.responsive(md-)}
} .responsive(...) {} .apply-responsive();

.responsive(@prefix) {
    @{prefix}block {display: block}
}

Und viele Variationen zwischen diesen drei oben, abhängig von der tatsächlichen Verwendung / den akzeptablen Ausführlichkeitsgrenzen der Implementierung gegenüber der Verwendung (z. B. für die Ausführlichkeit der Verwendung gewinnt die [3] -Methode sogar gegenüber parametrischen DRs, aber sie ist auf global beschränkt nur .resposive Definitionen, daher müssen alle verschachtelten Stile dorthin verschoben werden).

@seven-phases-max das ist alles super hilfreich, danke! Sie haben Recht, die erste Option funktioniert in meinem Fall perfekt, hatte nicht daran gedacht, & zu verwenden, um dies zu handhaben. Danke!

Offensichtlich muss es nicht das @-Zeichen sein (könnte ., ? usw. sein, aber keine arithmetischen oder relationalen Operatoren), und dann ist es nur das *( "Token", das eindeutig den Anfang der gesamten Konstruktion bezeichnet (glaube ich es wird viel einfacher und übrigens schneller für den Parser und die Augen sein

@( ist ein ziemlich schneller Ausgang für den Parser, da er nur ein Zeichen nach @ benötigt, um einen parametrischen DR zu bestimmen, aber ich zögere, @ für etwas anderes zu verwenden . Von den Symbolen über der obersten Reihe der Tastatur sind es wahrscheinlich !( , @( , $( , ^( , *( , =( . Ich denke, $ und ^ sind Nichtstarter, und =( sieht irgendwie traurig aus, also bleiben !( , @( , *( .

Mein einziges Zögern bei * ist, dass es auf den ersten Blick wie der Beginn einer mathematischen Operation aussieht (wenn auch einer unmöglichen), aber ich fühle mich nicht stark dabei.

Abgesehen davon denke ich, dass Ihre Instinkte gut sind, und ein einzelner Token-Bezeichner für parametrische DRs ist klug. Ich mag diese Idee und sie funktioniert gut mit separaten Bemühungen, das Mixin-/DR-Verhalten aufeinander abzustimmen. 👍

Wenn ich weiter darüber nachdenke, mag ich .( mehr, weil es genau so aussieht wie "Mixin ohne Namen" :) Obwohl mir klar ist, dass es wahrscheinlich besser ist, etwas auffälliger zu sein.

Ich poste dies nur für interessierte Parteien, um verschiedene Vor- und Nachteile der (manchmal ziemlich radikalen) Entscheidungen, die im Plugin getroffen wurden, auszuprobieren, bevor sie sich für Details der entsprechenden Kernfunktionen entscheiden

Inzwischen ist die Produktionsversion der zuvor erwähnten Plugin-basierten .for - und .for-each -Anweisungen in less-plugin-lists verfügbar. Sehen Sie sich die Dokumentation (verpassen Sie nicht den fortgeschrittenen Teil ) und die enthaltenen Tests ( 1 , 2 ) an.

Anmerkung: Dies sind wirklich Anweisungen , dh sie decken keine Anwendungsfälle einer Callback-orientierten for-each - Funktion ab (die auch implementiert werden soll ... nun, als Funktion, wenn wir tatsächlich parametrische Callbacks haben oder a irgendwie).

Dieses Problem wurde automatisch als veraltet markiert, da es in letzter Zeit keine Aktivität gab. Es wird geschlossen, wenn keine weiteren Aktivitäten stattfinden. Vielen Dank für Ihre Beiträge.

Dieses Problem wurde automatisch als veraltet markiert, da es in letzter Zeit keine Aktivität gab. Es wird geschlossen, wenn keine weiteren Aktivitäten stattfinden. Vielen Dank für Ihre Beiträge.

Ich bin auf diesen Bootstrap v4 Less-Port gestoßen, und das ist jemand, der Less offensichtlich sehr viel verwendet, und das Fehlen der for/each -Syntax in Less wurde auf der Eröffnungsseite angesprochen: https://github.com/seanCodes /bootstrap-less-port

Das heißt, es ist immer noch ein Problem. Ich denke, es gibt hier ein paar Starter-Threads, die Möglichkeiten bieten, aber ich frage mich, ob wir nicht etwas machen können, das gut mit Inline-Regelsätzen, getrennten Regelsätzen und Mixins funktioniert. Dies basiert auf einigen Kommentaren zu @seven-phases-max über die Nachteile des „Übergebens“ des Iterators in einer funktionsähnlichen Syntax. Stattdessen sollte es einfach am Ende stehen, entweder als einfacher Regelsatz oder als getrennte Regelsatz-Variable oder Mixin-Name.

Wie in:

[each syntax] [local vars] [ruleset|dr|mixin]

Also zum Beispiel:

.foo {
  :each(<strong i="13">@key</strong>, <strong i="14">@value</strong> in @list) {
    @{key}: @value;
  }
}

// or

<strong i="15">@dr</strong>: {
  @{key}: @value;
};
.foo {
  :each(<strong i="16">@key</strong>, <strong i="17">@value</strong> in @list) @dr;
}

// or
.mixin(<strong i="18">@key</strong>, @value) {
  @{key}: @value;
}
.foo {
  :each(<strong i="19">@key</strong>, <strong i="20">@value</strong> in @list) .mixin;  
  // or   :each(<strong i="21">@key</strong>, <strong i="22">@value</strong> in @list) > .mixin;  ?
}

Sie könnten auch, wie @arguments , <strong i="26">@key</strong>, @value injizieren, wenn nur @list bereitgestellt wird. Wie in:

.foo {
  :each(@list) .mixin
}

Ich bin mir nicht sicher, ob :each die richtige Syntax ist, aber ein einfaches each() macht keinen Sinn, weil es keine Funktionssyntax ist, und ich denke, wir stimmen bereits darin überein, dass @each() ist ein Nichtstarter für Less, der bereits @ für at-Regeln und Variablen- und Variablenaufrufe verwendet.

:each() würde einen "Special Behavior Selector" wie :extend() , was für mich sinnvoll ist. Gedanken willkommen.

Ich frage mich, ob sowohl :extend() als auch :each() nicht ::extend() und ::each() sein sollten, um die Pseudo-Selektoren ::before und ::after nachzuahmen each vorangestellt werden soll.

🤔 Auf den zweiten Blick ist :: unnötig. Es ist besser, die Syntax schlank zu halten.

🤔 Auf den zweiten Blick ist :: unnötig. Es ist besser, die Syntax schlank zu halten.

Zustimmen. Ich denke auch, dass es eher zu Pseudoklassen passt, die Parameter wie :not() und :nth-child() akzeptieren, und ich denke, dass :: ohnehin nur für Pseudoelemente verwendet wird (dh . Pseudoselektoren, die das eigentliche Ziel des Selektors ändern, anstatt die Liste der Übereinstimmungen zu ändern, wie ::before oder ::placeholder ).

Was :each() selbst betrifft, so gefällt mir dieser Vorschlag wirklich. Sehr "Weniger". Mixins sind definitiv ein Problem, aber ich frage mich, ob wir das für die anfängliche Implementierung als außerhalb des Geltungsbereichs bezeichnen. Ich denke, der Bedarf ist groß genug, dass eine reine DR-Lösung den Druck auf Bibliotheken wie Bootstrap-less-Port verringern würde.

Ich werde sagen, wie :extend() , es sollte ein echter Pseudoselektor sein, was bedeutet, dass wir &:each() anstelle von nur :each() benötigen sollten, wenn es verschachtelt ist.

.foo:each(<strong i="20">@list</strong> as <strong i="21">@i</strong>, @item) {
  &-@{i} { item: @item; }
}
// OR
.foo {
  &:each(<strong i="22">@list</strong> as <strong i="23">@i</strong>, @item) {
    &-@{i} { item: @item; }
  }
}

Eine andere Möglichkeit ist eine at-Regel, die ebenfalls bereits die Struktur [name] (params) {ruleset} in CSS hat. Ich gebe zu, fühlt sich nur ein bisschen "Sass-y" an, aber es sieht wirklich sauber aus.

<strong i="28">@each</strong> (<strong i="29">@list</strong> as <strong i="30">@i</strong>, @item) {
  .foo-@{i} { item: @item; }
}

Obwohl eigentlich die gleiche Sauberkeit mit & möglich sein sollte, solange :each() einen Null-"Basisselektor" zulässt.

&:each(<strong i="35">@list</strong> as <strong i="36">@i</strong>, @item) {
  .foo-@{i} { item: @item; }
}

Verkompliziert das, wie Leute über &:extend() denken, da dieser _keinen_ Basisselektor haben kann?

SIDEBAR: Dies ist ein Gedanke für einen anderen Thread und einen anderen Tag (wenn er überhaupt einen Wert hat), aber ich weiß, dass das Zögern mit mehr at-Regeln zukunftssicher ist. Es wäre wahrscheinlich eine Option (¿vielleicht --prefix-at-rules / -@ , vielleicht eine Liste von at-Regeln als Präfix?) und ich weiß, wie jeder es liebt, Optionen hinzuzufügen.


Lustigerweise ist @seanCodes , der Bootstrap-less-Port-Typ, mein Bruder. Ich werde versuchen, ihn hierher zu bekommen, damit er seine 2¢ hinzufügt.

Ich sage, wie bei :extend() sollte es ein echter Pseudoselektor sein, was bedeutet, dass wir &:each() anstelle von nur :each() benötigen sollten, wenn es verschachtelt ist.

_Lustigerweise_ neigte ich dazu, (separat) zu empfehlen, dass :extend &:extend nicht brauchen sollte. Ich meine, seine Bedeutung ist ohne & nicht zweideutig.

Aber in Bezug auf &:each müssen Sie bedenken, dass Sie vielleicht wollen, dass Schleifen von Listen überhaupt _Selektoren erstellen_. Aber .... Less macht nichts aus & an der Wurzel. 🤔

Eine andere Möglichkeit ist eine at-Regel, die ebenfalls bereits die Struktur [name] (params) {ruleset} in CSS hat. Ich gebe zu, fühlt sich nur ein bisschen "Sass-y" an, aber es sieht wirklich sauber aus.

Ja, du liegst nicht falsch. Und vielleicht ist @each semantisch ähnlicher zu @media . Ich kann mich nicht wirklich entscheiden, weil es kein echtes CSS-Äquivalent in der Sprache gibt. Es ist Funktionen wahrscheinlich ähnlicher, da es sich um eine Bewertungsanweisung handelt. Es ist nur so, dass Funktionen für diesen Anwendungsfall der Zuweisung zu einem Regelsatz umständlich sind.

Das Konzept ist hier nicht schwer; Es geht wirklich um die Syntax. Und vielleicht müssen wir nicht allergisch auf die Sass-Syntax reagieren. Ich frage mich nur, was die "deklarative Erweiterung" sein sollte.

Vielleicht ist &:each in der Tat nicht schlecht, weil Sie die Ergebnisse im Wesentlichen in den aktuellen Bereich, Selektor oder auf andere Weise zusammenführen.

Lustigerweise ist @seanCodes , der Bootstrap-less-Port-Typ, mein Bruder. Ich werde versuchen, ihn hierher zu bekommen, damit er seine 2¢ hinzufügt.

Ha! Kleine Welt! Warum ist er dann nicht auch im Less-Team? lol

@calvinjuarez

Einer meiner Lieblingssyntaxvorschläge in diesem Thread stammt von @seven-phases-max , wo er es funktionsähnlich macht, aber mit einer Zuweisung zu einem "Lambda", wie folgt:

each(@list): (@value) {
    box-shadow+: <strong i="9">@value</strong> black;
}

Das Schöne daran ist, dass es einfach sehr schlicht ist. Es ist funktionsähnlich und weist etwas zu, das wie ein anonymes Mixin aussieht. Sie haben wahrscheinlich Recht mit diesem Kommentar: „Mixins sind definitiv ein Problem, aber ich frage mich, ob wir das als Out-of-Scope für die anfängliche Implementierung bezeichnen. Ich denke, der Bedarf ist groß genug, dass eine reine DR-Lösung den Druck verringern würde Bibliotheken wie bootstrap-less-port."

Schließlich könnten Sie einfach tun:

each(@list): (@value) {
    .my-mixin(@value);
}

Und dann könnte Ihr inneres Mixin haben, wenn Wachen oder was auch immer für Werte an sie weitergegeben wurden. Abhängig von der Art Ihrer Liste könnte dies dann sein:

each(@list): (<strong i="17">@key</strong>, @value) {
   // Obvs can also just put your rules in here too
    .my-mixin(<strong i="18">@key</strong>, @value);
}

Ich frage mich, ob die Syntax von @seven-phases-max nicht besser ist als &:each oder :each , nur weil sie nicht unbedingt "mit einem Selektor zusammenhängt". Es ist eher eine funktionale Anweisung und überhaupt nicht wie :extend . Es fügt der Syntax auch nicht in oder as als Schlüsselwörter hinzu.

Ich meine, es ist schon ein paar Jahre her und diese Syntax sticht immer noch für mich heraus. Und es ist förderlicher für Konstruktionen wie:

.rules(@val) when (@val=warning) { ... }
.rules(@val) when (default()) { ... }

each(@selectors): (@value) {
  .badge-@{value} {
    .rules(@value);
  }
}

Das einzige Schlüsselwort, das ich hinzufügen könnte, ist so etwas wie das Schlüsselwort to dafür:

each(1 to 10): (@i) {
  <strong i="7">@val</strong>: extract(<strong i="8">@list</strong>, @i);
  .mixin(@val);
}

Und dann machen Sie natürlich 1 oder 10 nur Werte, also könnten Sie Folgendes tun:

<strong i="14">@start</strong>: 1;
each(<strong i="15">@start</strong> to length(@list)): (@i) {
  <strong i="16">@val</strong>: extract(<strong i="17">@list</strong>, @i);
  .mixin(@val);
}

Oh, noch etwas, wenn dies nur ein "anonymer Mixin" ist, sollten Sie in der Lage sein, Folgendes zu tun:

each(@colors): (@color) when (hue(@color) < 60) {
  background+: @color;
}

Das heißt, Mixins können Wachen haben, das ist alles. Es ist keine große Sache, aber es sollte nur aus Gründen der Konsistenz aufgerufen werden.

Einer meiner liebsten Syntaxvorschläge

Hmm, ich bin mir nicht sicher, ob ich in diese Syntax verliebt bin. Es fühlt sich für Less und CSS sehr fremd an und ist eigentlich rundum seltsam. Es ist fast, aber nicht ganz eine Funktion. Es scheint nur ein weiteres Konzept zu sein, um Menschen zum Lernen zu bewegen.

Es ist wirklich eher eine funktionale Anweisung ...

Mein Hauptanliegen dabei ist, dass (AFAIK) CSS niemals Funktionen verwendet, außer innerhalb von Eigenschaftswerten. Direktiven auf Root-Ebene sind immer at-Regeln.

Es fügt auch nicht in oder as als Schlüsselwörter zur Syntax hinzu.

Es sieht so aus, als würde es nur : anstelle eines Schlüsselworts verwenden. Was in Ordnung ist. Vielleicht schwerer zu lesen.

&:each(<strong i="15">@list</strong>:@i) {
  /* rules */
}
<strong i="16">@each</strong> (<strong i="17">@list</strong>:@i) {
  /* rules */
}

Lustigerweise war ich geneigt zu empfehlen (separat), dass :extend &:extend nicht brauchen sollte. Ich meine, seine Bedeutung ist ohne & nicht mehrdeutig.

Ich mag die & in &:extend . Es macht deutlich, dass :extend() eine Pseudo-Klasse ist. Die Erweiterung erfordert 2 Regeln (oder Selektoren, denke ich), die aktuelle und die zu erweiternde. Diese Syntax bindet :extend auf nette Weise an Selektoren. Ich bin mir nicht sicher, ob 1 Charakter die Mühe und konzeptionelle Verdrehung wert ist.

Das einzige Stichwort, das ich hinzufügen könnte ...

Ich mag to .

Als Nebenton fühlt sich das eher wie for und weniger wie each an. ("Jeder" scheint sich nur auf jeden einer Menge zu beziehen, dh Liste / Array, während sich "For" anfühlt, als würde es sich auf willkürlichere Indizes beziehen.) Ich denke, "for" ist aus semantischer Sicht ein flexibleres Wort .

Aber wirklich, da es hier nur um Syntax geht, denke ich, dass es am besten wäre, sich Sprachen zu leihen, die weniger Benutzer wahrscheinlich kennen.

<strong i="39">@for</strong> (<strong i="40">@i</strong> in @list) {
  <strong i="41">@item</strong>: extract(<strong i="42">@i</strong>, @list);
  /*stuff*/
}

Ein anderes, aussagekräftigeres Wort ist loop .

<strong i="47">@loop</strong> @list(<strong i="48">@i</strong>, @item) {
  /* stuff */
}

Wenn ich mehr über :each() nachdenke, glaube ich nicht, dass es & braucht. :extend() _hat_ etwas zu haben, das eine Erweiterung seines Parameters macht. Als "Selektor" allein macht es keinen Sinn. Aber das gilt nicht für _die meisten_ CSS-Pseudoklassen. :nth-child() , :not() , :lang() usw., _alle_ können alleine stehen und Bedeutung haben. Kein Grund, warum :each() das nicht kann. Tatsächlich ist :extend() in dieser Hinsicht irgendwie _seltsam_.

:each(<strong i="14">@list</strong> @i) { // no reason this should error
  /* stuff */
}

Die Kernfrage lautet also: @ , : oder eine Funktion/Beinahe-Funktion.

Mein Hauptanliegen dabei ist, dass (AFAIK) CSS niemals Funktionen verwendet, außer innerhalb von Eigenschaftswerten. Direktiven auf Root-Ebene sind immer at-Regeln.

Stimmt, aber ab Less 2.7 gibt es keine Einschränkungen, wo Funktionen aufgerufen werden können. Aber ich verstehe deinen Punkt.

Ich bin nicht gegen for , obwohl @for ..... 🤔 Ich meine, viele Sprachen verwenden forEach oder for-each . Und ja, ich denke, das ist alles, wo Less Ihrer Meinung nach im Sprachraum sitzt. Das Hinzufügen zur Sprache ist immer eine schwierige Entscheidung.

Ich denke, ich versuche herauszufinden, was parallel zu dem ist, was @cloudhead mit der Mixin-Guard-Syntax festgelegt hat, was eine sehr bewusste Wahl im Vergleich zu if war. Das heißt, es war ein "Bewerten Sie dies unter diesen Bedingungen". Es war eine Reihe von _Bedingungen_ für die Bewertung. Was if auch so gesehen werden könnte, ich möchte nur der Absicht der Sprache treu bleiben. Es ist eine große Veränderung, egal wie offensichtlich die Notwendigkeit ist.

Für mich vermittelt :each(<strong i="5">@list</strong> @i) {} oder :each(<strong i="7">@list</strong>: @i) { die iterative Natur der Auswertung nicht richtig. Es scheint eine einmalige Bewertung zu sein, dh @i entspricht dem vollen Wert von @list . Während etwas wie :each(@list): (@i) { } viel klarer macht, dass es eine Zuweisung zu einem Mixin-ähnlichen Konstrukt gibt.

Ich bin nicht gegen :each() vs. each() für den ersten Teil. Da bekomme ich die Bedenken.

Wie wäre es mit....

:each(@list) > (@val) { } 

Beleidigt > die Sprache weniger als : ? Du hast Recht, es gehört wahrscheinlich nicht dorthin. Ich denke, ich mochte einfach das "semantische Gefühl" der Syntaxkonstruktion.

--
Vielleicht ist :for(<strong i="23">@val</strong> in @list) { } noch sauberer? Du hast vielleicht recht, dass es besser funktioniert, als mit der Liste zu beginnen?

@seven-phases-max Hatte :for (<strong i="5">@val</strong> in @list) in diesem Kommentar zusammen mit anderen for Varianten.

@calvinjuarez Bevorzugen Sie etwas wie:

:for (<strong i="7">@val</strong> in @list) {}
:for (<strong i="8">@key</strong>, <strong i="9">@val</strong> in @list) {}
:for (<strong i="10">@i</strong> in 1 to 10) {}

Ich bin gespannt, was @seanCodes dazu zu sagen hat, was sich bei der Portierung von Bootstrap am logischsten und auch "weniger ähnlich" angefühlt hätte.

Ich möchte nur der Absicht der Sprache treu bleiben. Es ist eine große Veränderung, egal wie offensichtlich die Notwendigkeit ist.

Das ist ein guter Punkt. Was auch immer wir tun, kann nicht wirklich "rückgängig gemacht" werden. Ich denke, an diesem Punkt müssen wir wahrscheinlich mehr Input bekommen.

Das ist ein guter Punkt. Was auch immer wir tun, kann nicht wirklich "rückgängig gemacht" werden. Ich denke, an diesem Punkt müssen wir wahrscheinlich mehr Input bekommen.

Du hast Recht. Aber auch dieses Thema ist seit .... [blättert zurück] ... vier Jahren offen. Ich meine, irgendwann gibst du dein Bestes und triffst eine Entscheidung. Ich mag es jedoch, etwas zu erreichen, das dem Konsens nahe kommt.

Aber ja, es besteht keine Eile, mal sehen, ob es wieder Interesse gibt, zu einem Konsens zu kommen.

Bevorzugen Sie etwas wie: ...

Ja, ich denke, die sind alle wirklich sauber. Dies hat jedoch das von Ihnen erwähnte Keyword-Problem, bei dem in und to hinzugefügt werden. Aber ich denke, die Klarheit könnte die Kosten wert sein?

Ich bin gespannt, was @seanCodes zu sagen hat...

Dasselbe. Ich werde das Obige zitieren, damit er eine weitere Benachrichtigung erhält.

[blättert zurück] ... vier Jahre.

Wort.

Einer von euch wählt mit dem, was er damals konnte:
https://github.com/seven-phases-max/less-plugin-lists

@TigersWay - Was großartig ist, aber es verwendet auch das, was verfügbar war, dh es wird nichts erstellt, an dem der Parser erstickt wäre, also leiht es sich von der Mixin-Syntax. Idealerweise wäre da etwas Einheimisches. Obwohl dieses Problem seit vier Jahren offen ist, waren meiner Meinung nach weniger Schleifen ... weniger als ideal ... von Anfang an. Die meisten Schleifenbeispiele sind nur iterative Mixin-Guard-Hacks. Wieder nur meine Meinung.

Jawohl

zu dieser Zeit

Aber nach 4 Jahren ist das Abstimmen/Entscheiden mit 2 Seelen etwas kurz.
Und ich bin niemand :-)

Die meisten Schleifenbeispiele sind nur iterative Mixin-Guard-Hacks.

Keine Hacks; nur rekursionsbasierte Schleifen.
So würden Sie eine Schleife in einer funktionalen Programmiersprache schreiben.

Less stützt sich dank seines deklarativen Charakters ziemlich stark auf die FP-Prinzipien. Kontrast zur imperativen Natur von Sass.

Keine Hacks; nur rekursionsbasierte Schleifen. So würden Sie eine Schleife in einer funktionalen Programmiersprache schreiben.

@rjgotten Okay, fairer Punkt. Aber ich meine, dass sie zwar rekursiv ausgewertet werden können, aber zu einer umständlichen Syntaxkonstruktion führen. Aber um fair zu sein, sogar eine deklarative Templating-Sprache wie XSLT hat ein for-each -Tag. ( https://msdn.microsoft.com/en-us/library/ms256166 (v=vs.110).aspx) Eine Auswertung vom Typ for-each ist also nicht zwingend erforderlich. Selbst in Less ist es immer noch deklarativ, weil es im Wesentlichen die Iteration an die for-each -Auswertung „bindet“. Der einzige Unterschied in einem Imperativ for-each besteht darin, dass Sie so etwas tun können, wie den Status von Werten zu mutieren oder die Schleife zu unterbrechen. Bei einer deklarativen Schleifenauswertung wird jede Iteration "erweitert" und anhand einer Bedingung ausgewertet. Sie können die Schleife also niemals "unterbrechen", aber Sie können Bedingungen aufstellen, die einschränken, welche Werte passieren.

Mit anderen Worten, die Art, über for-each nachzudenken, wie es für Less gilt, ist wie folgt:

.rule {
  .mixin(extract(<strong i="15">@list</strong>, 1));   // This was an `each` call of some sort on <strong i="16">@list</strong>
  .mixin(extract(<strong i="17">@list</strong>, 2));
  .mixin(extract(<strong i="18">@list</strong>, 3));
  .mixin(extract(<strong i="19">@list</strong>, 4));
  .mixin(extract(<strong i="20">@list</strong>, 5));
  .mixin(extract(<strong i="21">@list</strong>, 6));
}

Alles wird ausgewertet und in die übergeordneten Regeln integriert. Deshalb habe ich mich für ein "anonymes Mixin"-Formular eingesetzt, das Wachen erlaubt.

Ich möchte sagen, dass ich Ihre Sorge teile, dass wir bei einer Syntax zögern sollten, die einer imperativen Form _ähnlich_ ist. Es sollte die Idee der "Erweiterung" der Liste in Anrufe klar kommunizieren. In Less würden Sie zum Beispiel nie etwas wollen wie:

<strong i="26">@for</strong> (<strong i="27">@i</strong> = 0; <strong i="28">@i</strong> < length(@list); <strong i="29">@i</strong> = <strong i="30">@i</strong> + 1) {}

Das ist _absolut_ zwingend und macht keinen Sinn. Insbesondere macht Less <strong i="33">@i</strong> = <strong i="34">@i</strong> + 1 keinen Sinn. Eine Variable kann einen Wert pro Gültigkeitsbereich haben. Eine deklarative Sprache kann oder sollte ihren eigenen Zustand nicht verändern.

:for (<strong i="37">@i</strong> in 1 to 10) {} ist ein wenig anders, weil @i ein einzelner Wert pro Mixin-Erweiterung zugewiesen wird .... aber .... es ist immer noch "imperativartig"; Aus diesem Grund bevorzuge ich eine Art "Aufgabe" von :each , wie :each(@list): (@val) oder :each(@list) > (@val) oder :for(@list):select(@val) oder so ähnlich.

@matthew-dean
Du hast absolut recht. Es gibt einen entscheidenden Unterschied zwischen einer harten imperativen for -Schleife und der eher deklarativen Natur einer for-each -Schleife. Ich wollte eigentlich mehr darüber schreiben, aber du bist mir zuvorgekommen.

@rjgotten ^_^ Da du diesen Thread eröffnet hast, hast du irgendwelche Vorschläge für die Zukunft? Es ist die Art von Funktion, die ich gerne sehen würde, aber die Syntax scheint wirklich schwierig zu sein, richtig zu sein.

@rjgotten Übrigens, als ich das noch einmal las, schrieben Sie:

Es scheint, dass LESS derzeit nur "reine" Regelsätze unterstützt, die als Mixin-Argumente weitergegeben oder als getrennte Regelsätze in Variablen gespeichert werden.

Ich sollte darauf hinweisen, dass ich in Less 3.5 Beta die Zuweisung von Mixin-Aufrufen zu Variablen implementiert oder sie an andere Mixins übergeben habe, gemäß dem Vorschlag in https://github.com/less/less-meta/issues/12.

Wie in:

.foo {
  <strong i="12">@call</strong>: .some-mixin(42);
  @call();
  .other-mixin(.some-mixin(42));
}

Hilft das diesem Problem überhaupt oder informiert es in Bezug auf die Richtung?

Hilft das diesem Problem überhaupt oder informiert es in Bezug auf die Richtung?

Nein, hilft leider nicht.

Damit Mixins als 'Lambdas' funktionieren können, müssen Sie in der Lage sein, das Mixin _selbst_ als Parameter zuzuweisen, nicht das _Ergebnis_ des Aufrufs des Mixins. Z.B

<strong i="9">@list</strong> : a b c;
.iteration-mixin(@item) {
  // does something with each <strong i="10">@item</strong> ...
}

:for-each(<strong i="11">@list</strong>, .iteration-mixin);

Und wenn wir die Vereinheitlichung von getrennten Regelsätzen und Mixins vollständig übernehmen und „anonyme Mixins“ (auch bekannt als getrennte Regelsätze) unterstützen können, die in der Lage sind, Parameter zu übernehmen, dann können wir folgende Syntax unterstützen:

<strong i="15">@list</strong> : a b c;
:for-each(<strong i="16">@list</strong>, (@item) {
   // does something with each <strong i="17">@item</strong> ...
});

Ich glaube, das wäre der Höhepunkt der benutzerfreundlichen Syntax, die die Sprache zum Durchlaufen von Listen bieten könnte.

@rjgotten Ich bin auch nicht gegen dieses Formular, von dem ich weiß, dass es dem ähnelt, was Sie zuerst eingeführt haben. Ich persönlich würde es wahrscheinlich lieber auf :each verkürzen. Gibt es etwas, das Ihrer Meinung nach semantisch oder deklarativ richtiger für for-each gegenüber each ist?

Aber pragmatisch gesehen verstehe ich, wo Sie hin wollen, um Konsistenz zu erreichen, und das Einfügen des Regelsatzes als Teil eines "Anruf" -Formulars ist nicht schlecht.

Ich stimme auch zu, wie Sie sich aus unseren Diskussionen in anderen Threads vorstellen können, in der verallgemeinerten Form von (@var) { } , die ein Sprachkonstrukt sein könnte, das überall verwendet wird (als "anonyme Mixins").

Wären Sie gegen diese Form?

<strong i="14">@list</strong> : a b c;
:each(<strong i="15">@list</strong>, (@item) {
   // ...
});
:each(<strong i="16">@list</strong>, (<strong i="17">@item</strong>, @key) {
   // ...
});

Ich bin ein wenig besorgt darüber, wo dies in den Sprachraum neben :extend() und & when passt.

Ich mag @each einfach nicht. Ich bin nicht gegen eine einfache each() -Funktion, da das Parsing weniger Änderungen erfordert (wenn getrennte Regelsätze zulässige Argumente wären), aber ich verstehe auch den Pushback von einigen, die einfache Funktionen an der Wurzel sehen. Schön, dass diese Diskussion trotzdem weitergeht!

Oh, das gefällt mir! Ich denke, wenn wir nur den Regelsatz übergeben, sollte es eine Funktion sein. Ich denke nicht, dass wir ein weiteres Selektor-ähnliches Feature einführen sollten, das keinen Regelsatz akzeptiert. :extend(); ist auf diese Weise wirklich seltsam.

@calvinjuarez Kannst du das klären? Sie würden angesichts dieser Parameter für eine einfache each() -Funktion plädieren?

Du weisst; Wenn Sie darüber nachdenken, dann _ist_ :each( ... ) wirklich nur eine einfache Funktion an der Wurzel.
Es ist eine Funktion namens ":each" (einschließlich Doppelpunkt).
In Bezug auf die Implementierung sollte es also keinen wirklichen Unterschied geben, oder? Wenn ja, dann könnte die Funktion einfach auf mit/ohne Doppelpunkt und vielleicht sogar auf beides umgeschaltet werden, wobei der Doppelpunkt optional ist.

Das bringt mich zu einem anderen Punkt: Vielleicht sollten wir diesen Doppelpunkt zu einem optionalen Feature für _jeden_ gerooteten Funktionsaufruf machen?

Sehen Sie sich zuerst eine nicht gerootete Funktion an: property : func( ... )
Und dann schauen Sie sich eine gerootete Funktion an: : func( ... )

Es ist dasselbe, mit einem Unterschied: Bei der gerooteten Version fehlt die linke Seite, weil das Ergebnis tatsächlich _direkt_ dem aktuellen Gültigkeitsbereich zugewiesen wird, dh in diesen ausgegeben wird, und nicht einer Eigenschaft zugewiesen wird.

@rjgotten Sie können bereits seit 2.7 Funktionen in die Wurzel legen. Ich bin mir nicht sicher, warum wir den Doppelpunkt für jede Funktion optional machen sollten? Halten Sie das in Bezug auf die Syntax für vorzuziehen?

Hinsichtlich der Implementierung würde es eine kleine Änderung im Parser für die Funktionserkennung geben, wenn ein Doppelpunkt optional wäre, aber das ist kein Grund, dies nicht zu tun, wenn es für diesen Fall bevorzugt wird.

Eine Sache, wir können Plugin-Autoren klarer mitteilen, dass Sie Funktionen in die Wurzel packen KÖNNEN, wenn wir es zu einer einfachen each() -Funktion machen.

Wenn ich darüber nachdenke, sollten wir hier vielleicht auf das Doppelpunkt-Präfix verzichten.
Es kann zu Mehrdeutigkeiten in der Grammatik führen, da es Pseudoklassen wie :nth-child() ähnelt

Und wirklich; niemand möchte die Kopfschmerzen haben, sich irgendwo später noch einmal damit befassen zu müssen.

Wenn ich darüber nachdenke, sollten wir hier vielleicht auf das Doppelpunkt-Präfix verzichten.
Es kann zu Mehrdeutigkeiten in der Grammatik führen, da es Pseudoklassen wie :nth-child() ähnelt.

👍

Okay, sind wir dem Konsens näher, dies zu einer eingebauten each() -Funktion zu machen, die das übergibt, was wir entweder ein "anonymes Mixin" oder einen "abgelösten Regelsatz mit Parametern" nennen? Ich denke, es sollte in der Codebasis eher letzteres sein, bis wir die beiden Regelsatz-Aufruftypen vereinheitlichen können.

Wenn wir uns näher sind, möchte ich diese Frage posten:

Da jemand möglicherweise Schlüssel-/Wertlisten hat oder einen Index haben möchte, ist dies eher der "weniger Weg" ->

each(<strong i="13">@list</strong>, (@value) { }); // and...
each(<strong i="14">@list</strong>, (<strong i="15">@key</strong>, @value) { });
// or
each(<strong i="16">@list</strong>, (@value) { }); // and...
each(<strong i="17">@list</strong>, (<strong i="18">@value</strong>, @key) { });

Im Gegensatz zu JavaScript ist bei Less die Anzahl der Argumente signifikant. Es gibt also keinen programmatischen Grund, den Wert immer an die erste Stelle zu setzen, da der Schlüssel nicht _gesetzt_ (als Parameter übergeben) wird, es sei denn, es gibt eine _passende Definition_.

Also bin ich geneigt zu sagen, dass (<strong i="22">@key</strong>, @value) weniger-y ist. Wenn Sie 2 Argumente in Ihrer Definition haben, werden 2 Argumente übergeben. Wenn nicht, wird der Wert übergeben.

Ich würde mich eigentlich für (<strong i="5">@value</strong>, @key) , da @value in 99% der Fälle das ist, worüber Sie iterieren werden, und @key eine sekundäre Sache ist, die Sie möglicherweise in verwenden Prozess.

Es hat auch Parität mit forEach Iteration in JavaScript.
Und obwohl Less kein JavaScript ist; Seien wir ehrlich, beide arbeiten im Front-End und es wird dort viele Instanzen von gemeinsamem Mind-Space für Entwickler geben. Könnte es ihnen auch leichter machen.

Ich würde mich eigentlich für (<strong i="6">@value</strong>, @key) , da @value in 99% der Fälle das ist, worüber Sie iterieren werden, und @key eine sekundäre Sache ist, die Sie möglicherweise in verwenden Prozess.

Das ist ok für mich. Ich bin gut mit dem Argument, dass @key sekundär ist und nicht ausschließlich über JS-Parität, obwohl es in Ordnung ist, dass es den Mind-Space teilt, wie Sie sagen.

Ich mag, wo das ist! Ja, ich bin für die einfache Funktion.

each(<strong i="6">@list</strong>, (<strong i="7">@item</strong>, @i) {});

Schlicht und einfach.

@rjgotten @calvinjuarez

Übrigens habe ich vor etwas mehr als zwei Jahren eine Version davon ohne Parsing-Änderungen erstellt. Sehen Sie sich die Commits in diesem Zweig an: https://github.com/matthew-dean/less.js/tree/feature/each

Die Art und Weise, wie ich es ohne Parsing-Änderungen gemacht habe, ist, dass der zweite Parameter eine Liste sein könnte, wie in: each(@list; key, value; {}); Buuuut, ich weiß, dass das nicht ideal ist.

Die Sache ist, wenn wir wollen, dass (<strong i="12">@item</strong>, @i) {} ein legitimer Wert ist, sehe ich ein paar Probleme:

  1. Ist (<strong i="16">@item</strong>, @i) {} eine Art getrennter Regelsatzwert, der überall verwendet werden kann? Wenn es nur mit each() verwendet wird und mit keiner anderen Funktion verwendet werden kann, warum?
  2. Wenn es anderweitig verwendet werden kann, was ist es? Ist es ein Mixin oder ein getrennter Regelsatz, weil a) wenn es sich um einen getrennten Regelsatz handelt, die Regeln für Argumente nicht trivial sind. Wenn es nicht die gleichen Argumente wie Mixins sind, warum nicht? b) Wenn es ein Mixin ist, wie funktioniert das? Kann es Wachen haben? Grundsätzlich muss dieser ganze Thread gelöst werden: https://github.com/less/less-meta/issues/16

Grundsätzlich würde diese Form einen Regelsatz eher wie ein Mixin machen, was in Ordnung ist, da wir ein "Ding" machen wollen. Aber dann muss ein einziges Regelwerk definiert werden.

Wir könnten also eine Lösung finden, indem wir diese "Form" des Werts nirgendwo anders zulassen und das eingebaute each() mit Sonderfällen versehen. (Dies wäre nicht die einzige Sonderfallfunktion, da if "When-Bedingungen" empfangen kann und keine andere Funktion.) Alternativ könnten wir Parsing-Änderungen vermeiden und 2 spezielle Variablen "injizieren". der Block, genau wie @arguments jetzt ist. Das ist im Wesentlichen das, was ich standardmäßig in meiner Implementierung getan habe. Wir könnten @key und @value in jede Iteration des Regelsatzes einfügen. Ehrlich gesagt ist das am einfachsten, weil ich die Arbeit schon erledigt habe lol.

Das Einfachste, was heute implementiert werden kann, ist im Grunde genommen:

each(<strong i="30">@list</strong>, {
  prop-@{key}: @value;
});

Es sei denn, wir analysieren jeden Sonderfall, aber Sonderfälle und eine neue Regel für jedes Argument brauchen Zeit.

Gedanken?

Gedanken?

Das Einfügen der beiden Parameter scheint als erster Schritt in Ordnung zu sein, um das Feature zum Laufen zu bringen, und dann erneut darauf einzugehen, um die richtigen benutzerkonfigurierbaren Parameternamen hinzuzufügen, sobald die Probleme mit dem getrennten Regelsatz im Hinblick auf Mixins geklärt sind.

@rjgotten

Das Einfügen der beiden Parameter scheint als erster Schritt in Ordnung zu sein, um das Feature zum Laufen zu bringen, und dann erneut darauf einzugehen, um die richtigen benutzerkonfigurierbaren Parameternamen hinzuzufügen, sobald die Probleme mit dem getrennten Regelsatz im Hinblick auf Mixins geklärt sind.

Das ist okay für mich. @key und @value okay?

Wenn wir nur Listen durchlaufen wollen, würde ich @index statt @key verwenden,
Wenn wir das Durchschleifen von Eigenschaften (z. B. eines getrennten Regelsatzes, der als Karte/Wörterbuch verwendet wird) unterstützen, ist das allgemeinere @key angemessener.

Wenn wir das Durchschleifen von Eigenschaften (z. B. eines getrennten Regelsatzes, der als Karte/Wörterbuch verwendet wird) unterstützen, ist das allgemeinere @key besser geeignet.

Genau das dachte ich; dass es Schleifen über Listen oder Regelsätze-als-Maps unterstützen würde.

@rjgotten Wir könnten je nach Listentyp auch einen anderen Variablennamen einfügen, solange dokumentiert wurde, welcher verwendet werden soll. Es wäre trivial festzustellen, ob es sich um einen Regelsatz handelt oder nicht, da die Liste.

Eigentlich möchten wir vielleicht @key AND @index (und @value ) tun, falls jemand etwas mit der Position einer Regel in einer Karte machen möchte. Für einfache Listen könnte der Wert von @key für die geringste Überraschung auf @index gesetzt werden.

@matthew-dean
(...)
Du hast absolut recht. 'Regelsätze als Karten' sind per Definition geordnete Karten, also macht ein Index auch für sie Sinn.

Eigentlich möchten wir vielleicht @key AND @index (und @value) machen, falls jemand etwas mit der Position einer Regel in einer Karte machen möchte.

Da frage ich mich, was @index im Zusammenhang mit einer Karte bedeutet. Das heißt, in einer Listenschleife könnten Sie extract() aufrufen und den Index übergeben. Es scheint, als ob auf diese Weise viele Vorbehalte und Inkonsistenzen eingeführt wurden (z. B. funktioniert extract(@looped-thing, @index) in einigen Schleifen, aber nicht in allen).

<strong i="13">@map</strong>: {
  foo: bar;
  baz: qux;
};
each(<strong i="14">@map</strong>, {
  -less-log: extract(<strong i="15">@map</strong>, @index); // → ???
  // Or would this mean anything? (Certainly after a unification of access and extract that I've seen floated.)
  -less-log: @map[@index]; // → ???
})

Bei der Implementierung bin ich also auf ein Problem mit verschachtelten each() gestoßen und habe mich gefragt, ob wir benannte Parameter benötigen. Bei einem Versuch, Parameter mit (<strong i="7">@value</strong>, @key) { } zu benennen, stellte ich fest, dass das für das Parsen viiiel mehrdeutig war, wenn wir später "anonyme Mixins" oder "getrennte Regelsätze mit Argumenten" machen wollten. Sobald Sie <strong i="9">@dr</strong>: (@value ... bis dahin schreiben, könnte dies mit <strong i="11">@dr</strong>: (<strong i="12">@value</strong> + 1); oder <strong i="14">@dr</strong>: (<strong i="15">@value</strong>, @key) { } enden, sodass ein Backtracking erzwungen wird.

Das heißt, zwei Punkte:

  1. Benannte Variablen sind erforderlich, wenn Sie jemals each() -Funktionen verschachteln möchten. Als erste Implementierung werden sie wahrscheinlich nicht benötigt? Vielleicht nicht zuerst die Verschachtelung ansprechen? Aber wenn Sie sie später wollen ... wie werden wir injizierte vs. deklarierte in Einklang bringen?
  2. Ich wollte nur darauf hinweisen, dass dieses Formular für anonyme Mixins/Dr-Argumente <strong i="22">@dr</strong>: (<strong i="23">@value</strong>, @key) { } wirklich zu zweideutig ist.

Vielleicht gibt es in Zukunft mehr davon:

<strong i="27">@dr</strong>: #(<strong i="28">@arg1</strong>, @arg2) { };
@dr(1, 2);

each(<strong i="29">@list</strong>, #(<strong i="30">@value</strong>, @key) { });

Also, die Sache ist, wenn Sie jemals verschachteln WOLLEN, dann ist das Injizieren von vars vielleicht der falsche Ansatz. Und wenn Sie benannte Variablen benötigen, dann ist nur ein einfaches (<strong i="33">@value</strong>, @key) { } für DR-Argumente der falsche Ansatz IMO für Less.

Oder vielleicht ist dies der falsche Ansatz, um each() zu unterstützen. Ich weiß nicht...

<strong i="6">@dr</strong>: #(<strong i="7">@arg1</strong>, @arg2) { };

Ich habe über einen Spezifizierer nachgedacht, um deutlich zu machen, dass Sie ein Mixin definieren. Ich denke, . sollte auch akzeptabel sein, da standardmäßige "unbekannte" Mixins entweder . oder # zulassen.

Mit anderen Worten, konzeptionell erweitern wir nur das _aktuelle_ Mixin-Formular, um kein Zeichen nach . oder # einzufügen, obwohl sie sich insofern nicht so verhalten würden, wie Standard-Mixins es tun würden wären nicht "vom Autor aufrufbar" und sie würden kein "Überladen" zulassen (weil sie einzigartige einmalige Mixins definieren würden, anstatt Ergänzungen zu bestehenden.

@calvinjuarez

Deshalb frage ich mich, was @index im Kontext einer Karte bedeutet. Das heißt, in einer Listenschleife könnten Sie extract() aufrufen und den Index übergeben. Es scheint, als würden auf diese Weise viele Vorbehalte und Inkonsistenzen erzeugt.

Ich sehe keine Inkonsistenzen, die dort produziert werden. Sie können Ihr Beispiel in etwas ändern, das mit der aktuellen PR funktioniert.

<strong i="11">@map</strong>: {
  foo: bar;
  baz: qux;
};
.box {
  each(<strong i="12">@map</strong>, {
    -less-log: @map[$@key]; 
  })
}

Ausgänge:

.box {
  -less-log: bar;
  -less-log: qux;
}

Sie können auch Folgendes tun:

<strong i="19">@list</strong>: a b c d;
.box {
  each(<strong i="20">@list</strong>, {
    -less-log: extract(<strong i="21">@list</strong>, @index);
  })
}

Welche Ausgänge:

.box {
  -less-log: a;
  -less-log: b;
  -less-log: c;
  -less-log: d;
}

Oder weisen Sie nur darauf hin, dass Sie @index bis extract() nicht auf einer Karte verwenden können? Denn ich denke, das ist ein ganz anderes Thema.

Mit anderen Worten, wir erweitern konzeptionell nur das aktuelle Mixin-Formular, um kein Zeichen nach dem . oder #, obwohl sie sich nicht wie Standard-Mixins verhalten würden, da sie nicht "vom Autor aufrufbar" wären.

Könnte wahrscheinlich irgendwann vom Autor aufrufbar sein, aber nicht aufrufbar könnte für diesen ersten Anwendungsfall funktionieren? Ich habe mich gefragt, was ich nehmen soll: #( oder .( , aber ich mag die Idee von entweder/oder.

-less-log: @map[$@key];

$@var funktioniert!? Ich hatte keine Ahnung! Ich dachte, es wäre nixed! Das macht mich so glücklich!

$@ funktioniert!? Ich hatte keine Ahnung! Ich dachte, es wäre nixed! Das macht mich so glücklich!

Ha, ja, ich habe es in Fehlerkorrekturen gesteckt, bevor ich 3.5 veröffentlicht habe. ^_^

Könnte wahrscheinlich irgendwann vom Autor aufrufbar sein, aber nicht aufrufbar könnte für diesen ersten Anwendungsfall funktionieren?

Ich würde denken, "anonym" würde "nicht vom Autor aufrufbar" vorschlagen, aber vielleicht ist "anonym" nicht das Wort. Vielleicht ist das etwas anderes.

Außerdem (und ich habe auch den anderen Kommentar mit diesem Gedanken bearbeitet, aber ich werde ihn hier einfügen, damit er nicht so versteckt ist), denke ich, dass der _große_ Unterschied darin besteht, dass .(){} und #(){} wäre nicht überlastbar/stapelbar.

each(@list1; .(<strong i="11">@value</strong>, <strong i="12">@key</strong>, @i) {})
each(@list2; .(<strong i="13">@value</strong>, <strong i="14">@key</strong>, @i) {}) // this mixin probably shouldn't overload, right?

Und _das_ würde bedeuten, dass Autoren keine spezifische Möglichkeit hätten, auf ein bestimmtes .(){} -Mixin zu verweisen und es aufzurufen, was bedeutet, dass sie "anonym" sind, und wir können sie einfach so nennen.

@calvinjuarez

Würden wir das nicht irgendwann tun?

<strong i="8">@mixin</strong>: #(<strong i="9">@op1</strong>, @op2) {
  value: <strong i="10">@op1</strong> + @op2;
}
@mixin(2px, 1px);

Der Grund dafür ist, was Sie gesagt haben: dh Vars sind nicht überladbar. Sie könnten also Mixins im Wesentlichen "ersetzen", indem Sie die Variable neu zuweisen.

<strong i="14">@mixin</strong>: #(<strong i="15">@op1</strong>, @op2) {
  value: <strong i="16">@op1</strong> + @op2;
}
& {
  <strong i="17">@mixin</strong>: #(<strong i="18">@op1</strong>, @op2) {
    value: <strong i="19">@op1</strong> - @op2;
  }
  @mixin(2px, 1px);
}

Scheint ein ziemlich nützliches Muster zu sein. Sie könnten auch Mixin-Definitionen an andere Mixins weitergeben, was Sie jetzt nicht tun können. (In 3.5 können Sie Mixin-_Aufrufe_, dh den resultierenden Regelsatz, an ein Mixin übergeben, aber keine Definitionen.) Das war es, wohin ich damit wollte; das ist der Grund, warum ein Präfix benötigt wird.

Wenn getrennte Regelsätze nützlich sind, um herumgereicht und aufgerufen zu werden, dann ist es sinnvoll, dass Regelsätze mit Argumenten genauso nützlich/leistungsfähig sind, wenn nicht sogar noch mehr.

Deshalb möchte ich, dass dieses Muster, wenn es für each() verwendet wird, etwas ist, das irgendwann verallgemeinert werden könnte.

Ich würde denken, "anonym" würde "nicht vom Autor aufrufbar" vorschlagen.

Das „anonym“ in „anonymous function“ rührt daher, dass es ohne eigene benannte Referenz aufgebaut ist.

Ohne eine eigene benannte Referenz kann nicht direkt über Name by Code an anderen Stellen darauf zugegriffen werden. In diesem Sinne ist eine solche Funktion "nicht _direkt_ vom Autor aufrufbar", aber immer noch aufrufbar, wenn der Autor die ursprüngliche Funktionsreferenz einer Variablen zuweist.

Also ja; "anonymous mixin" ist hier definitiv die richtige Terminologie.

@rjgotten Danke, das ist eine großartige Erklärung.

Was haltet ihr von der Syntaxoptimierung / PR?

Ich denke, das hinzugefügte # oder . macht sehr viel Sinn und nicht nur aus Sicht der Parser-Begriffsklärung.

.( a ) { } ist zu .foo( a) { } in weniger als function( a ) { } zu function foo( a ) { } in JavaScript.

Es lautet wörtlich: "Hier deklariere ich ein Mixin" ( das führende . ) "dem ich keinen Namen zur weiteren Bezugnahme geben werde."

Die einzige alternative Syntax, die Sinn machen würde, ist meiner Meinung nach, die Pfeilfunktionssyntax von JS, C# usw. zu klonen und wie folgt zu gestalten:

each(@list; (<strong i="16">@value</strong>, <strong i="17">@key</strong>, @index) => { })

Das würde auch funktionieren, ist aber wahrscheinlich viel schwieriger zu implementieren, da es viel vorausschauendes Durchsuchen der Argumentliste erfordert, um die Markierung => zu finden, während Sie die Markierung .( oder #( finden

Das würde auch funktionieren, ist aber wahrscheinlich viel schwieriger zu implementieren, da es viel vorausschauendes Durchsuchen der Argumentliste erfordert, um die Markierung => zu finden, während Sie die Sequenz .( oder #( am Kopf finden, die Sie bereits kennen Sie würden es mit einem anonymen Mixin zu tun haben, ohne dass viel Vorausschau erforderlich ist.

Ich meine, das ist mein Hauptgrund; #() / .() ist einfach einfacher zu implementieren, aber ich würde es nicht vorantreiben, wenn die Syntax nicht bei den Leuten ankommen würde. Wenn es geliert, funktioniert es meiner Meinung nach wie erwartet in https://github.com/less/less.js/pull/3263. Bitte bei Gelegenheit prüfen!

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen