Beim googlen habe ich festgestellt, dass die Verwendung von while
loops oder die Verwendung von Variablen nicht empfohlen wird.
Nun habe ich einen sehr einfachen Algorithmus implementiert, der Zeichen aus einem Eingabestream liest und entsprechend analysiert: Wenn die Eingabe 10:abcdefghej
ist, wird 10
analysiert und dann die nächsten 10 Bytes nach dem Doppelpunkt gelesen.
Das Ding, mit dem ich irgendwie verloren bin, ist, wie ich das umgestalten kann, so dass es nicht auf Variablen beruht.
%Vor% Ich verstehe auch, dass die einzige Möglichkeit, Variablen zu deklarieren, das Schlüsselwort with-local-vars
ist. Ist es nicht unpraktisch, am Anfang alle Variablen in einem Block zu definieren, oder fehlt mir ein entscheidender Punkt?
Ein bisschen spät zu dieser Party, nehme ich an, aber das Problem ist viel einfacher, wenn Sie die Zeichenfolge nur als eine Folge von Zeichen behandeln und Clojures Sequenz-Handling-Primitive verwenden:
%Vor%Eine Zusammenfassung:
before
und after
zu binden, und streichen Sie die :
aus, während wir dabei sind, indem Sie sie an eine unbenutzte lokale Komponente mit dem Namen colon
für die Beschreibung binden. before
, um seinen numerischen Wert zu erhalten after
und zerquetsche sie alle zu einer Zeichenkette mit (apply str)
Svantes Antwort ist ein hervorragendes Beispiel dafür, wie man mit Clojure loop-isch Code schreibt; Ich hoffe, dass meins ein gutes Beispiel dafür ist, die eingebauten Funktionen so zusammenzustellen, dass sie genau das tun, was Sie brauchen. Sicherlich lassen beide die C-Lösung alles andere als "sehr einfach" aussehen!
Was Sie schreiben, ist C-Code mit lisp-artiger Syntax (nichts für ungut). Einen Stil zu definieren, indem man nicht tut ist sehr definierend, aber es ist nicht sehr hilfreich, wenn man nicht weiß, "wie, sonst wie?"
Übrigens, ich weiß nicht, was indicator
tun soll.
So würde ich dieses Problem angehen:
Das Problem besteht aus zwei Teilen: Finden Sie die Anzahl der zu lesenden Zeichen und lesen Sie dann diese vielen Zeichen. Daher würde ich zwei Funktionen schreiben: read-count
und read-item
, wobei letztere die erstere verwendet.
read-item
muss zuerst die Anzahl der zu lesenden Zeichen bestimmen. Dazu verwendet es die bequeme Funktion read-count
, die wir ebenfalls definieren.
Das Schleifen wird in Clojure im Allgemeinen am besten gehandhabt, indem loop
und recur
verwendet werden. loop
bindet auch Variablen wie let
. acc
soll die gelesenen Elemente ansammeln, beachten Sie jedoch, dass es nicht an Ort und Stelle geändert wird, sondern jede Iteration neu gebunden wird.
Nun müssen wir etwas in dieser Schleife tun: bind c
an das nächste Zeichen, aber return acc
, wenn count
0 ist. (zero? count)
ist dasselbe wie (= count 0)
. Ich habe die if
-Form für diejenigen, die damit nicht vertraut sind, kommentiert.
Jetzt brauchen wir nur noch die Funktion read-count
. Es verwendet eine ähnliche Schleife.
Testen Sie es auf der REPL, debuggen, refactor. Liefert .read
wirklich Zeichen zurück? Gibt es eine bessere Möglichkeit, eine ganze Zahl zu analysieren?
Ich habe das nicht getestet, und ich bin etwas behindert, weil ich weder Erfahrung noch tiefe Kenntnisse von Clojure habe (ich benutze meistens Common Lisp), aber ich denke, dass es zeigt, wie man sich dieser Art von Problem in einer "Lispy" nähert "Weise. Beachten Sie, wie ich Variablen nicht deklarieren oder ändern kann.
Idomatic Clojure eignet sich sehr gut zum Arbeiten mit Sequenzen. In C tendiere ich dazu, in Begriffen von Variablen zu denken oder den Zustand einer Variablen mehrmals zu ändern. In Clojure denke ich in Sequenzen. In diesem Fall würde ich das Problem in drei Abstraktionsschichten aufteilen:
stream zu Bytes:
%Vor%Bytes zu Zeichen
%Vor%Zeichenfolgen [chars]
%Vor%Dies wird träge bewertet, so dass jedes Mal, wenn die nächste Zeichenkette benötigt wird, diese aus dem Eingabestrom gezogen und konstruiert wird. Sie könnten dies beispielsweise in einem Netzwerkstream verwenden, ohne den gesamten Stream zuerst puffern zu müssen oder sich darum sorgen zu müssen, dass der Code, der von diesem Stream gelesen wird, sich Gedanken darüber macht, wie er aufgebaut ist.
ps: ich bin im Moment nicht an meiner REPL, also bitte editieren, um irgendwelche Fehler zu beheben:)
Ich lerne Clojure selbst, also nimm das nicht als Guru-Rat, sondern als Rat eines Kommilitonen.
Clojure ist eine funktionale Programmiersprache. Funktionale Programmierung bedeutet keine Schleifen, keine Variablen und keine Nebenwirkungen. Wenn Sie jemals von diesen drei Regeln abweichen, brauchen Sie sehr gute Gründe dafür und gültige Gründe sind ziemlich selten.
Sie sind offensichtlich ein sehr geübter Programmierer, also schauen Sie sich diese Informationen an und Sie sollten hoffentlich eine bessere Vorstellung davon bekommen, wie sich funktionales Design von objektorientiertem Design unterscheidet.
Auch würde ich empfehlen, einen Clojure-Code anzuschauen, hier ist ein Beispielprogramm, auf dem gehostet wird github.com wurde geschrieben, um Teil eines clojure Screencast-Tutorials zu sein.
Das Screencast-Tutorial, für das der Code gedacht war, kann hier gefunden werden, ist aber nicht kostenlos:
(Ich bin sowieso nicht mit peepcode.com verbunden).
Viel Glück mit Clojure!