簡體   English   中英

Clojure變量和循環

[英]Clojure Variables and Looping

通過谷歌搜索,我發現不鼓勵使用while循環或使用變量。

現在,我實現了一個非常簡單的算法,該算法將從輸入流中讀取字符並進行相應的解析:如果輸入為10:abcdefghej ,它將解析出10個字符,然后在冒號之后讀取下一個10個字節。

我有點迷失的是如何重構它,使其不依賴變量。


(defn decode-string [input-stream indicator]

  (with-local-vars [length (str (char indicator) )
            delimiter (.read input-stream ) 
            string (str "")
            counter 0 ]

    (while (not(= (var-get delimiter) 58 ))
       (var-set length (str (var-get length) (char (var-get delimiter)) ))
       (var-set delimiter (.read input-stream )))

    (var-set length (new BigInteger (var-get length)) )
    (var-set counter (var-get length))

    (while (not(zero? (var-get counter) ))
       (var-set string (str (var-get string) (char (.read input-stream ))  ))
       (var-set counter (dec (var-get counter))))
    (var-get string)))

另外,我知道聲明變量的唯一方法是使用with-local-vars關鍵字。 在開始時在一個塊中定義所有變量是不切實際的,還是我錯過了一些關鍵點?

您正在編寫的是具有類似Lisp語法的C代碼(無意冒犯)。 用您不做的事情來定義樣式是非常定義的,但是如果您不知道“好吧,那還有什么呢?”並沒有太大幫助。

順便說一句,我不知道應該做什么indicator

這就是我解決這個問題的方法:

  1. 該問題分為兩部分:找到要讀取的字符數,然后讀取那么多字符。 因此,我將編寫兩個函數: read-countread-item ,后者使用前者。

    \n (defn讀取計數[流]\n   ;;  去做\n   \n\n (defn閱讀項目[流]\n   ;;  去做\n   \n
  2. read-item首先需要確定要讀取的字符數。 為此,它使用了我們還將定義的便捷函數read-count

    \n (defn閱讀項目[流]\n   (讓[count(讀計數流)]\n     ;;  去做\n     ))\n
  3. 通常在Clojure中最好使用looprecur處理loop loop還綁定變量,如let acc旨在累積讀取的項目,但請注意,它並未就位修改,而是在每次迭代時重新綁定。

    \n (defn閱讀項目[流]\n   (循環[計數(讀計數流)\n          acc“”]\n     ;;  去做\n     (重復(十進制計數);新的計數值\n            (str acc c)))));  acc的新值\n
  4. 現在,我們需要在該循環中執行以下操作:將c綁定到下一個字符,但是當count為0時返回acc(zero? count)(= count 0) 我為那些不熟悉它的人添加了if格式。

    \n (defn閱讀項目[流]\n   (循環[計數(讀計數流)\n          acc“”]\n     (如果(零?計數);條件\n         acc;  然后\n         (讓[c(.read stream)]; \\\n           (遞歸(十進制計數);>其他\n                  (str acc c))))))));  /\n
  5. 現在,我們需要的只是read-count功能。 它使用類似的循環。

    \n (defn讀取計數[流]\n   (循環[計數0]\n     (讓[c(.read流)]\n       (如果(= c“:”)\n           計數\n           (重復(+(*計數10)\n                     (整數/ parseInt c))))))))\n
  6. 在REPL上進行測試,調試,重構。 .read是否真的返回字符? 有沒有更好的方法來解析整數?

我沒有對此進行測試,沒有任何經驗或對Clojure的深入了解(我主要使用Common Lisp)使我有點受阻,但是我認為它顯示了如何以“輕率”的方式解決此類問題。 請注意,我不考慮聲明或修改變量。

我想這晚了一點,但是如果您僅將字符串視為字符序列並使用Clojure的序列處理原語,則問題會簡單得多:

(defn read-prefixed-string [stream]
  (let [s (repeatedly #(char (.read stream)))
        [before [colon & after]] (split-with (complement #{\:}) s)
        num-chars (read-string (apply str before))]
    (apply str (take num-chars after))))

user> (let [in (java.io.StringReader. "10:abcdefghij5:klmnopqrstuvwxyz")]
        (repeatedly 2 #(read-prefixed-string in)))
("abcdefghij" "klmno")

總結:

  • 將丑陋的,有副作用的輸入流轉換為懶惰的字符序列,以便我們可以將其假裝為此操作其余部分的字符串。 如您所見,從流中實際讀取的字符不超過計算結果所需的字符。
  • 將字符串分成兩部分:前半個字符在第一個冒號之前,后半部分剩下的內容。
  • 使用解構將這些部分綁定到命名為beforeafter局部語言,並通過將其綁定到未使用的局部命名空間colon來描述,從而去除:
  • before閱讀以獲取其數值
  • after獲取那么多字符,並使用(apply str)它們融合在一起成為一個字符串

Svante的答案是一個很好的例子,說明了如何使用Clojure編寫循環式代碼。 我希望我的例子是組裝內置功能的好例子,以便它們執行您需要的操作。 當然,這兩者都使C解決方案看起來“非常簡單”!

Idomatic Clojure確實使它適合於使用序列。 在C語言中,我傾向於考慮變量或改變變量狀態多次。 在Clojure中,我認為是序列。 在這種情況下,我會將問題分為三個抽象層:

  • 將流轉換為字節序列。
  • 將字節序列轉換為字符序列
  • 將字符序列轉換為字符串序列。

流到字節:

defn byte-seq [rdr]  
  "create a lazy seq of bytes in a file and close the file at the end"  
  (let [result (. rdr read)]  
    (if (= result -1)  
      (do (. rdr close) nil)  
      (lazy-seq (cons result (byte-seq rdr))))))  

字節為字符

(defn bytes-to-chars [bytes]
  (map char bytes))

字符到字符串[字符]

(defn chars-to-strings [chars]
   (let [length-str (take-wile (#{1234567890} %) chars)
         length (Integer/parseInt length-str)
         length-of-lengh (inc (count length-str)) 
         str-seq (drop length-of-length chars)]
        (lazy-seq 
          (cons
            (take length str-seq)
            (recur (drop (+ length-of-length length) chars))))))

這是惰性計算的,因此每當需要下一個字符串時,它將從輸入流中提取並構造。 例如,您可以在網絡流上使用它,而不必先緩沖整個流,也不必擔心從該流讀取代碼,而不必擔心其結構。

ps:目前我還不是我的REPL,所以請編輯以修復所有錯誤:)

我本人正在學習Clojure,因此請不要將此作為大師的建議,而應作為同學的建議。

Clojure是一種功能編程語言。 函數式編程意味着沒有循環,沒有變量並且沒有副作用。 如果您偏離了這三個規則,則需要非常充分的理由,而很少有有效的理由。

您顯然是一個非常熟練的程序員,因此請查看此信息,並希望您能更多地了解功能設計與面向對象設計的不同之處。

http://en.wikibooks.org/wiki/Clojure_Programming/Concepts#Sequence_Functions

另外,我建議您查看一些clojure代碼,這是托管在github.com上的示例程序,該程序編寫為clojure屏幕廣播教程的一部分。

http://github.com/technomancy/mire/tree/master

可以在此處找到代碼的截屏教程,但它不是免費的:

http://peepcode.com/products/functional-programming-with-clojure

(無論如何我都不隸屬於peepcode.com)。

Clojure祝您好運!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM