lisp - Clojure 变量和循环

标签 lisp clojure variables loops

通过谷歌搜索,我发现不鼓励使用 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 关键字。一开始就在一个 block 中定义所有变量是不是有点不切实际,还是我错过了一些关键点?

最佳答案

您正在编写的是具有类似 lisp 语法的 C 代码(无意冒犯)。用你不做来定义风格是非常明确的,但如果你不知道“好吧,那又如何呢?”这不是很有帮助

顺便说一下,我不知道 indicator 应该做什么。

这就是我解决这个问题的方法:

  1. 问题分为两部分:找到要读取的字符数,然后读取那么多字符。因此,我会写两个函数:read-countread-item,后者使用前者。

    (defn read-count [stream]
      ;; todo
      )
    
    (defn read-item [stream]
      ;; todo
      )
    
  2. read-item首先需要确定要读取的字符数。为此,它使用我们也将定义的便捷函数 read-count

    (defn read-item [stream]
      (let [count (read-count stream)]
        ;; todo
        ))
    
  3. 在 Clojure 中,循环通常最好通过使用 looprecur 来处理。 loop 也绑定(bind)变量,如 letacc的意思是累加读取的item,但是注意不是原地修改而是每次迭代都重新绑定(bind)。

    (defn read-item [stream]
      (loop [count (read-count stream)
             acc ""]
        ;; todo
        (recur (dec count)        ; new value for count
               (str acc c)))))    ; new value for acc
    
  4. 现在我们需要在那个循环中做一些事情:将 c 绑定(bind)到下一个字符,但是当 count 是时返回 acc 0. (zero?count)(= count 0) 相同。我为那些不熟悉它的人对 if 形式做了一些注释。

    (defn read-item [stream]
      (loop [count (read-count stream)
             acc ""]
        (if (zero? count)                  ; condition
            acc                            ; then
            (let [c (.read stream)]        ; \
              (recur (dec count)           ;  > else
                     (str acc c)))))))     ; /
    
  5. 现在我们只需要read-count 函数。它使用类似的循环。

    (defn read-count [stream]
      (loop [count 0]
        (let [c (.read stream)]
          (if (= c ":")
              count
              (recur (+ (* count 10)
                        (Integer/parseInt c)))))))
    
  6. 在 REPL 上测试、调试、重构。 .read 真的返回字符吗?有没有更好的方法来解析整数?

我还没有测试过这个,我对 Clojure 没有任何经验和深入了解(我主要使用 Common Lisp)有点受阻,但我认为它展示了如何在“lispy”中解决此类问题“方式。请注意我是如何不考虑声明或修改变量的。

关于lisp - Clojure 变量和循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1054170/

相关文章:

Clojure - map 索引是否可以从 0 以外的索引开始?

javascript - 如何在javascript中将字符串值转换为变量?

ios - 获取整数的相同实例

list - 检查列表是否包含重复项的谓词

clojure - 为什么 Clojure 的反向函数返回一个非惰性序列?

lisp - 定义用于评估 Lisp 中缀表达式的函数

clojure - ClojureScript 中的 pretty-print 嵌套 HashMap

clojure 需要带括号的作品

variables - 如何在clojure宏中绑定(bind)var的名称和值?

javascript - 我如何在 HTML 中使用这个 JavaScript 变量?