Frage

OK, kein Betrug jetzt.

Nein, wirklich, eine Minute dauern oder zwei und versucht, diese aus.

Was bedeutet "Positionen" tun?

Edit:. Vereinfacht nach cgrand Vorschlag

(defn redux [[current next] flag] [(if flag current next) (inc next)])

(defn positions [coll]
  (map first (reductions redux [1 2] (map = coll (rest coll)))))

Nun, wie über diese Version?

def positions(coll) {
  def (current, next) = [1, 1]
  def previous = coll[0]
  coll.collect {
    current = (it == previous) ? current : next
    next++
    previous = it
    current
  }
}

Ich lerne Clojure und ich liebe es, weil ich immer funktionale Programmierung genossen habe. Es hat mich mehr mit der Clojure Lösung zu kommen, aber ich habe mit zu denkt eine elegante Lösung. Die Groovy-Lösung ist in Ordnung, aber ich bin an dem Punkt, wo ich diese Art von imperativen Programmierung finden langweilig und mechanisch. Nach 12 Jahren Java, ich fühle mich in einer Furche und funktionale Programmierung mit Clojure ist die Boost ich brauchte.

Richtig, auf den Punkt. Nun, ich muss ehrlich sein und sagen, dass ich frage mich, ob ich die Clojure Code verstehen werde, wenn ich später es Monate zurück. Ich konnte das Heck aus es sicher sagen, aber ich brauche nicht meinen Java-Code zu kommentieren, es zu verstehen.

Also meine Frage ist: ist es eine Frage von mehr funktionalen Programmierung Muster gewöhnen? Sind funktionale Programmierung Gurus diesen Code zu lesen und es ein Kinderspiel zu finden, zu verstehen? Welche Version hat Sie finden leichter zu verstehen?

Edit: was dieser Code tut, ist, die Positionen der Spieler berechnen entsprechend ihrer Punkte, während im Auge behalten diejenigen, die gebunden sind. Zum Beispiel:


Pos Points
1. 36
1. 36
1. 36
4. 34
5. 32
5. 32
5. 32
8. 30
War es hilfreich?

Lösung

Ich glaube nicht, dass es so etwas wie intrinsische Lesbarkeit. Es ist das, was Sie gewohnt sind, und was Sie nicht verwendet werden. Ich war in der Lage, beide Versionen des Codes OK zu lesen. Ich konnte tatsächlich Ihre Groovy Version leichter lesen, obwohl ich nicht weiß, Groovy, weil ich zu einem Jahrzehnte Blick auf C und Java und nur ein Jahr Blick auf Clojure verbracht. Das sagt nichts über die Sprachen, es sagt nur etwas über mich.

Ebenso kann ich Englisch leichter als Spanisch lesen, aber das sagt nichts über die innere Lesbarkeit dieser beiden Sprachen. (Spanisch ist tatsächlich wohl die „lesbare“ Sprache des beide in Bezug auf Einfachheit und Konsistenz, aber ich kann immer noch es nicht gelesen). Ich lerne Japanisch jetzt und ein Heck einer harten Zeit, aber einheimische japanische Sprecher sagen das gleiche über Englisch.

Wenn Sie die meisten Ihres Lebens verbrachte Java zu lesen, natürlich Dinge, die aussehen wie Java einfacher sein wird, als die Dinge zu lesen, die nicht tun. Bis Sie so viel Zeit mit der Suche in Lispy Sprachen Blick auf C-ähnliche Sprachen ausgegeben haben, wird dies wohl wahr bleiben.

Um eine Sprache zu verstehen, unter anderem Sie müssen vertraut sein mit:

  • Syntax ([vector] vs. (list), hyphens-in-names)
  • Wortschatz (was tut reductions bedeuten? Wie / wo kann man es sehen?)
  • Bewertungsregeln (tut Funktionen als Objekte Arbeit behandeln? Es ist ein Fehler in den meisten Sprachen.)
  • Idiome, wie (map first (some set of reductions with extra accumulated values))

Alle diese einige Zeit dauern und Praxis und Wiederholung zu lernen und zu verinnerlichen. Aber wenn Sie die nächsten 6 Monate Lesen und Schreiben viel Clojure verbringen, nicht nur Sie in der Lage, dass Clojure Code 6 Monate ab jetzt zu verstehen, werden Sie wahrscheinlich es besser verstehen, als Sie jetzt tun, und vielleicht sogar in der Lage sein, zu vereinfachen es. Wie wäre es damit:

(use 'clojure.contrib.seq-utils)                                        ;;'
(defn positions [coll]
  (mapcat #(repeat (count %) (inc (ffirst %)))
          (partition-by second (indexed coll))))

Mit Blick auf Clojure Code schrieb ich vor einem Jahr, bin ich entsetzt, wie schlimm es ist, aber ich kann es lesen OK. (Nicht, dass Ihre Clojure Code ist schrecklich;. Ich hatte keine Probleme es überhaupt zu lesen, und ich bin kein Guru)

Andere Tipps

Ich bin mit Timothy: Sie zu viel Abstraktionen einzuführen. Ich überarbeitete Code und endete mit:

(defn positions [coll]
  (reductions (fn [[_ prev-score :as prev] [_ score :as curr]] 
                (if (= prev-score score) prev curr))
    (map vector (iterate inc 1) coll)))

über den Code,

(defn use-prev [[a b]] (= a b))
(defn pairs [coll] (partition 2 1 coll))
(map use-prev (pairs coll))

kann einfach als Refactoring:

(map = coll (rest coll))

bearbeiten. kann nicht mehr relevant sein

Die Clojure man mir gewunden. Es enthält mehr Abstraktionen, die verstanden werden müssen. Dies ist der Preis für Funktionen höherer Ordnung verwenden, müssen Sie wissen, was sie bedeuten. So in einem Einzelfall erfordert zwingend notwendig, weniger Wissen. Aber die Macht der Abstraktion ist in ihrer Trägermittel-Kombination. Jeder Imperativ Schleife gelesen und verstanden werden muss, während Sequenz Abstraktionen können Sie die Komplexität einer Schleife entfernen und leistungsstarke opperations kombinieren.

Ich würde weiter argumentieren, dass die Groovy Version zumindest teilweise funktional wie collect verwendet, die wirklich Karte, eine Funktion höherer Ordnung. Es hat einigen Zustand in ihm auch.

Hier ist, wie ich die Clojure Version schreiben würde:

(defn positions2 [coll]
  (let [current (atom 1)
        if-same #(if (= %1 %2) @current (reset! current (inc %3)))]
    (map if-same (cons (first coll) coll) coll (range (count coll)))))

Das ist ganz ähnlich wie die Groovy Version, dass sie ein veränderliches „Strom“ verwendet, unterscheidet sich aber dadurch, dass es nicht um einen nächsten / vorherigen Variable hat - stattdessen unveränderliche Sequenzen für die Verwendung. Als Brian elloquently es ausdrückte, ist die Lesbarkeit nicht intrinsische. Diese Version ist meine Vorliebe für diesen speziellen Fall, und scheint irgendwo in der Mitte zu sitzen.

Die Clojure ist man auf den ersten Blick mehr gewunden; obwohl es vielleicht eleganter. OO ist das Ergebnis Sprache mehr „zuordenbar“ auf höherer Ebene zu machen. Funktionale Sprachen scheinen eine „algorithimc“ zu haben (primitives / schlecht) Gefühl. Das ist genau das, was ich im Moment fühlte. das wird sich ändern, wenn ich mehr Erfahrung in der Arbeit mit clojure haben vielleicht.

Ich habe Angst, dass wir in das Spiel sind decending von welcher Sprache die knappste sein kann oder ein Problem in der am wenigsten Codezeile lösen.

Das Problem sind zwei Falten für mich:

  1. Wie einfach auf den ersten Blick ein Gefühl von dem, was der Code tut ?. Dies ist wichtig für die Code-Maintainer.

  2. Wie einfach es an der Logik hinter dem Code zu erraten ist ?. Zu ausführlich / langatmige ?. Zu kurz und bündig?

"Make alles so einfach wie möglich, aber nicht einfacher."

Albert Einstein

Auch ich lerne Clojure und lieben es. Aber in dieser Phase meiner Entwicklung war die Groovy Version leichter zu verstehen. Was Ich mag über Clojure ist aber, den Code zu lesen und das mit „Aha!“ Erfahrung, wenn man endlich „get“, was los ist. Was ich wirklich zu genießen, ist die ähnliche Erfahrung, die ein paar Minuten später passiert, wenn man alle Möglichkeiten, den Code erkennen, um den Code ohne Änderungen auch auf andere Arten von Daten angewendet werden könnten. Ich habe Zählung der Anzahl der Male verlor ich durch einige numerische Code in Clojure gearbeitet habe und dann, etwas später, daran dachte, wie das gleiche Code könnte mit Streichern, Symbolen, Widgets verwendet werden, ...

Die Analogie ich benutze, ist über Farben zu lernen. Denken Sie daran, wenn Sie auf die Farbe Rot eingeführt wurden? Sie verstanden es ziemlich schnell - es gibt alles rot Sachen in der Welt. Dann hörte man den Begriff Magenta und wurde für eine Weile verloren. Aber noch einmal, nach einer wenig mehr Aufmerksamkeit, verstand man das Konzept und hatte eine viel präzise Art und Weise eine bestimmte Farbe zu beschreiben. Sie müssen das Konzept verinnerlichen, halten eine in den Kopf mehr Informationen biß, aber Sie mit etwas leistungsstärker und prägnant enden.

unterstützt Groovy verschiedene Arten der Lösung dieses Problems zu:

coll.groupBy{it}.inject([]){ c, n -> c + [c.size() + 1] * n.value.size() }

definitiv Refactoring nicht zu hübsch sein, aber nicht zu schwer zu verstehen.

Ich weiß, dass dies auf die Frage keine Antwort, aber ich in der Lage, „verstehen“ den Code viel besser, wenn es Tests gibt, wie zum Beispiel:

assert positions([1]) == [1]
assert positions([2, 1]) == [1, 2]
assert positions([2, 2, 1]) == [1, 1, 3]
assert positions([3, 2, 1]) == [1, 2, 3]
assert positions([2, 2, 2, 1]) == [1, 1, 1, 4]

Das wird mir sagen, ein Jahr ab jetzt, was der Code erwartet wird, zu tun. Viel besser als jede ausgezeichnete Version des Code, den ich hier gesehen habe.

Am I wirklich off topic?

Die andere Sache ist, glaube ich „Lesbarkeit“ hängt vom Kontext ab. Es hängt davon ab, die den Code beibehalten wird. Zum Beispiel, um den „functional“ -Version des Groovy-Code (aber brillant) aufrecht zu erhalten, wird es nicht nur Groovy Programmierer, aber funktionell Groovy-Programmierer ... Die andere, relevantere Beispiel ist: Wenn ein paar Zeilen Code, um es einfacher verstehen für „Anfänger“ Clojure Programmierer zu machen, dann werden der Code insgesamt mehr lesbar sein, da sie von einer größeren Gemeinschaft verstanden werden: keine Notwendigkeit, studiert haben Clojure für drei Jahre in der Lage zu sein, die Code und machen Änderungen, um es zu erreichen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top