2016-02-11 2 views
10

Ich finde mich oft in einer Situation, wo ich interessiere mich nicht wirklich, ob ich einen Vektor oder eine Karte:Warum funktionieren Keys und Vals nicht an Vektoren?

[:foo :bar :baz :qux] 
{0 :foo, 1 :bar, 2 :baz, 3 :qux} 

wichtige Funktionen (get, assoc, etc.) auf beiden arbeiten. Einige, wie dissoc, arbeiten nicht auf Vektoren, aber sie haben gute Gründe nicht zu.

Aber ich einfach nicht verstehen, warum keys und vals Arbeit auf Karten und nicht auf Vektoren. Gibt es einen guten Grund, warum sie nicht so umgesetzt werden (oder vielleicht mit einer eleganteren, polymorphen Lösung)?

(defn keys [m] 
    (if (vector? m) 
    (seq (range (count m))) 
    (clojure.lang.RT/keys m))) 

(defn vals [m] 
    (if (vector? m) 
    (seq m) 
    (clojure.lang.RT/vals m))) 

Wenn es keinen guten Grund gibt, wie kann ich versuchen, dies in Standard Clojure implementiert zu bekommen?

Antwort

5

Ich denke, es ist eine gültige Idee, die einen Verdienst hat.

Die Frage, mit welchen Funktionen gearbeitet werden sollte und was ein Fehler sein sollte, ist schwierig, eine Zeile zu zeichnen. Am einen Ende kann eine Sprache übermäßig permissiv sein (JavaScript?) Bis zu dem Punkt, an dem es dir erlaubt, dich selbst zu verletzen. Am anderen Ende kann es so präskriptiv sein, dass Sie keine starken Abstraktionen haben, die komponieren (C?).

In diesem speziellen Fall tauschen wir die Fähigkeit aus, einen Fehler zu erkennen, wenn Sie Code schreiben, der eine Karte erwartet, aber einen Vektor passiert; gegen den Vorteil, mehr generischen Code schreiben zu können. Persönlich mag ich, dass es als ein Fehler behandelt wird, weil ich manchmal die falsche Art der Sammlung zu einer Funktion übergebe, und es vorziehe, um zu explodieren, als etwas zu tun.

Ich würde es verwirrend finden, keys auf einem Vektor zu nennen, weil ein Vektor keine Schlüssel hat, ist es indexierbar. Für mich sind das verschiedene Dinge. Wenn ich Code schreibe, der keys auf einem Vektor aufruft, ist es wahrscheinlich ein Fehler. Wenn ich wirklich einen Bereich haben möchte, der die gleiche Größe wie der Vektor hat, würde ich das explizit schreiben. Und wenn ich eine Funktion haben wollte, die sowohl Karten als auch Vektoren verarbeiten könnte, würde ich eine Typ-Bedingung verwenden, um Schlüssel oder Bereichsanzahl zu wählen. Offensichtlich sind dies nur meine Vorlieben, aber für mich sind sie ein wichtiger Grund, nicht an keys auf Vektoren arbeiten zu wollen. Der Grund ist, dass ich Fehler erkennen möchte.

Es ist jedoch völlig verständlich, dass Sie lieber mit Vektoren arbeiten würden, da sie assoziativ nach Index sind.

Wie für sollte dissoc auch funktionieren, könnte jemand anderes behaupten, warum nicht? (dissoc [1 2 3] 0) -> [2 3]) Es gibt ein Leistungsproblem, weil Sie Elemente in O (1) nicht entfernen können, nicht wirklich, wenn Clojure rbb-vector adoptierte. Manchmal ist es sehr praktisch, wenn Sie diese Operation ausführen müssen. Es ist something people need to do, und ist ziemlich hässlich und undurchsichtig in Clojure! Keiner von uns möchte, dass dies ein Feature ist, aber ich wette, dass es in einigen Situationen wirklich elegant sein würde. Aber es ist nicht wirklich eine technische Einschränkung, wir bevorzugen es einfach so.

Clojure hat einen offenen Prozess contribution, der auf kocht. Besprechen Sie, was Sie mit anderen auf der Clojure Dev Google-Gruppe zu tun versuchen. Sie werden wahrscheinlich in der Lage sein, Kommentare und Vorschläge anzubieten, die zu einer besseren Qualität und einem reibungsloseren Einreichungsverfahren führen. Sobald Sie die Zertifizierungsstelle eingereicht haben, können Sie Patches über JIRA senden.

Jeder kann einen Fehler oder eine Verbesserungsanfrage an Clojure senden. Jeder, der die Contributor-Vereinbarung unterzeichnet hat, kann Patches bereitstellen oder an der Verbesserung der Tickets arbeiten. Screeners haben die Möglichkeit erhalten, Tickets durch (einige) Phasen des Prozesses zu verschieben. BDFL - Rich Hickey ist der Schöpfer und Wohltätige Diktator für das Leben von dem, was in Clojure geht. Stuart Halloway hat auch eine spezielle Ebene des Zugangs und typischerweise Patches für Clojure.

Wenn Sie glauben, dass dies eine gute Änderung für Clojure wäre, empfehle ich, es zuerst in der Clojure Group zu diskutieren, um Unterstützung für die Idee zu erhalten und sie dann der Clojure Dev Group zu bringen. Im Allgemeinen wird Ihre Idee am besten empfangen, wenn unterstützende Artefakte wie "Hier ist ein großartiger Anwendungsfall, wo es Wert zeigt" und "Hier ist eine Diskussion, wo andere Leute das gleiche Wertversprechen wünschen" angeboten werden.

+3

Ich stimme dem Sentiment zu, aber ich denke, das größte Problem wäre, dass es die Vektordarstellungen von Karten in Frage stellen würde, zB '(seq {: foo: bar, 1 2}) => [[: foo: bar] [1 2] ' Angesichts dieser Änderung würde ich erwarten ' (in {} [: foo: bar 1 2]) => {0: foo, 1: bar, 2 1, 3 2 } ' das ist eigentlich ziemlich verwirrend IMO –

+1

Nur um zu klären, das Problem mit dem Vektor' dissoc', wie Sie es vorgeschlagen haben, ist das (disso [1 2 3] 0) 'würde zurückkehren' [2 3] ', die wäre äquivalent zur Karte '{0 2, 1 3}'. Auf der anderen Seite würde '(dissoc {0 1, 1 2, 2 3} 0)' {1 2, 2 3} 'zurückgeben, was eine völlig andere Karte ist. –

+1

Anders sicher, aber warum ist das ein Problem? –

1

Als Hintergrund re der Sammlung Modell: http://insideclojure.org/2016/03/16/collections/

Keys und vals sind beide als Funktionen definiert, die eine seqable von Map-Einträge nehmen. Angesichts dieser Definition ist es nicht einfach möglich, sie auf eine Sammlung mit dem assoziativen Merkmal zu erweitern, da ein sammlungartiger Vektor keine Folge von Einträgen erzeugt, sondern eher eine Folge von Vektorwerten. Die Fähigkeit, Einträge zu mappen, wird nur von Karten bereitgestellt.

Ja, es wäre möglich, eine Funktion zu erstellen, die entweder funktioniert, aber ich denke, dies würde den bestehenden Vertrag dieser Funktionen brechen, nicht erweitern.

Um die Design-Frage, ob es auf diese Weise oder nicht in erster Linie hätte getan werden sollen, ist es schwieriger für mich zu sagen.

Verwandte Themen