Wie konvertiere ich diesen JavaScript-Code in Clojure?

Ich versuche, eine (x, y) Welt zu zeichnen, in der die Zellen entsprechend der Fülleigenschaft ein- oder ausgeschaltet sind. Im folgenden Beispiel versuche ich, die Zeilen und dann die Spalten zu drucken, aber mein nächster Schritt besteht darin, die Fülleigenschaft zu verschieben (nach oben, unten, links, rechts). Ich möchte also keine Antwort, die nicht funktionieren würde, wenn ich die Datenstruktur nicht drucken würde.

Mein Ziel ist es zu verstehen, wie man über dieses Problem auf funktionale Weise nachdenkt. Es war einfach für mich, dieses Problem mit veränderlichem Zustand in JavaScript zu lösen. Während ich an der Lösung arbeitete, konnte ich leicht überlegen, wie der Code in JavaScript geschrieben werden soll, aber als ich in Clojure das Gleiche tat, war ich ratlos. Ich denke, eine gute Antwort auf diese Frage wäre, mir zu helfen, zu verstehen, wie ich über diese Art von Problem auf funktionale Weise nachdenken kann.

Ich habe viele Vorträge gesehen und eine Reihe von Artikeln über Clojure und funktionale Programmierung gelesen, aber wenn es darum geht, den Code zu schreiben, fällt es mir schwer, damit anzufangen.

var world = [
    [{ x: 1, y: 4, fill:0 }, { x: 2, y: 4, fill:0 }, { x: 3, y: 4, fill:0 }, { x: 4, y: 4, fill:0 }],
    [{ x: 1, y: 3, fill:0 }, { x: 2, y: 3, fill:0 }, { x: 3, y: 3, fill:0 }, { x: 4, y: 3, fill:0 }],
    [{ x: 1, y: 2, fill:0 }, { x: 2, y: 2, fill:0 }, { x: 3, y: 2, fill:0 }, { x: 4, y: 2, fill:0 }],
    [{ x: 1, y: 1, fill:0 }, { x: 2, y: 1, fill:0 }, { x: 3, y: 1, fill:1 }, { x: 4, y: 1, fill:0 }]
];

function printworld(world) {
    var out = "";
    for(var row=0; row<world.length; row++) {
        for(var col=0; col<world[row].length; col++) {
            out += "["+world[row][col].fill+"]";
        }
        out += "\n"
    }
    console.log(out);
}

printworld(world);

Die Ausgabe sieht aus wie:

[0][0][0][0]
[0][0][0][0]
[0][0][0][0]
[0][0][1][0]

BEARBEITEN: Nachdem ich einige Zeit bei 4clojure.com mit der Bearbeitung der Probleme verbracht hatte, stellte ich fest, dass ich versuchte, ein größeres Problem (z. B. ein Schachspiel in Clojure) abzubeißen, als ich zu lösen bereit war. Das Erstellen der grundlegendsten Funktionen bei 4clojure.com war schwierig, aber es baut ein stetiges Wissen darüber auf, wie man mit der Funktionsmethode an eine Lösung herangeht.

1
buddyw 5 Dez. 2013 im 18:37

3 Antworten

Beste Antwort

Wie fange ich an, funktional zu denken? Es gibt keine Abkürzungen und schnelle Antworten. Sie müssen viel Zeit investieren, um funktional zu programmieren.

Sie können beginnen, indem Sie einfache Algorithmen verwandeln. Es ist jedoch wichtig zu beachten, dass Sie sich bei der funktionalen Programmierung um den Datenfluss kümmern und nicht darum, wie Sie die CPU anweisen, dies und das zu tun.

Es ist wichtig, die Kernfunktionen in Ihrer Sprache zu kennen. Mit diesen Kernfunktionen können Sie beginnen, Ihre Daten zu transformieren. Art von Lego- oder DNA-Streifen, wenn Sie möchten.

Wenn Sie sich besonders für Clojure interessieren, empfehle ich Ihnen, eine gute Zeit mit 4Clojure und Land of Lisp zu verbringen.

Und Clojure IRC ist ein wunderbarer Ort, um von Rockstars Clojure-Entwicklern zu lernen. Freundliche Gemeinschaft und auf jeden Fall hilfreich.

Denken Sie immer daran: "OOP ist standardmäßig nicht einfach und FP ist standardmäßig nicht schwer".

3
Chiron 5 Dez. 2013 im 17:26

Nun, die Daten werden mehr oder weniger identisch aussehen:

(def world [[{:x 1, :y 2, :fill 0}, {:x 2, :y 2, :fill 0}]
            [{:x 1, :y 1, :fill 0}, {:x 2, :y 2, :fill 1}]])

Für die Druckfunktion können Sie jedoch doseq verwenden.

(defn print-world [world]
  (doseq [row world]
    (doseq [cell row]
      (print (str "[" (:fill cell) "]")))
    (println)))

(print-world world)

;; outputs
;; [0][0]
;; [0][1]

Und um Elemente zu ändern, assoc-in oder update-in

; move the filled cell 'up'
(print-world
  (-> world
    (assoc-in [1 1 :fill] 0)     ; set bottom-right fill to 0
    (assoc-in [0 1 :fill] 1)))   ; set top-right fill to 1

;; outputs
;; [0][1]
;; [0][0]

Clojure ist nicht die beste Lösung für diese Art der Programmierung, aber es ist nützlich zu wissen.

Bearbeiten: Was das funktionale Denken betrifft, so ist dies nicht die Art von Fähigkeit, die leicht durch eine Stackoverflow-Antwort vermittelt werden kann. Es erfordert viel Code zu schreiben und den Code anderer Leute zu lesen. Ein großartiger Ort, um online zu beginnen, wäre Clojure für die Tapferen und Wahren. Das, was mich funktional zum Nachdenken gebracht hat, war das wundervolle Lernen Sie ein Haskell zum Wohle! “.

1
d.j.sheldrick 5 Dez. 2013 im 15:05

Diese Skizze erzeugt die Zustände der Welt, anstatt eine Struktur im Gedächtnis zu mutieren. In Rich Hickey Speak wird der nächste Wert generiert, anstatt etwas anderes am selben alten Ort zu speichern.

// world is an object with the world's state
var world = function(tl, tr, bl, br){
    this.state = {topLeft: tl, topRight: tr, bottomLeft: bl, bottomRight: br};
};

// screen is an object with internal state that represents
// the state of the of the world
var screen = function(aWorld){
    this.state = [[{fill: aWorld.state.topLeft},
           {fill: aWorld.state.topRight}],
          [{fill: aWorld.state.bottomLeft},
           {fill: aWorld.state.bottomRight}]];
};

// showScreen is a function in which all side
// effects occur.
function showScreen(aScreen){
    var out = "";
    for (var line = 0; line < aScreen.state.length; line++){
    for (var pix = 0; pix < aScreen.state[line].length; pix++){
        out += "[" + aScreen.state[line][pix].fill + "]";
    }
    out += "\n"
    }
    console.log(out);
}

// here is the heart of functional style programming:
// generating the next value instead of changing
// some existing state
function nextWorld(tr,tl,br,bl){
    showScreen(new screen(new world(tr,tl,br,bl)))
}

// turn off screen
function screenOff(){
    nextWorld(0,0,0,0)
}

// make a forward slash
function forwardSlash(){
    nextWorld(1,0,0,1)
}
0
ben rudgers 6 Dez. 2013 im 14:07