Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/jsf-2/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Lisp Clojure变量和循环_Lisp_Clojure_Variables_Loops - Fatal编程技术网

Lisp Clojure变量和循环

Lisp Clojure变量和循环,lisp,clojure,variables,loops,Lisp,Clojure,Variables,Loops,通过谷歌搜索,我发现不鼓励使用while循环或使用变量 现在我实现了一个非常简单的算法,它将从输入流中读取字符并进行相应的解析:如果输入是10:abcdefghej,它将解析出10,然后读取冒号后的下一个10字节 我有点迷茫的是如何重构它,使它不依赖于变量 (defn decode-string [input-stream indicator] (with-local-vars [length (str (char indicator) ) delimiter (

通过谷歌搜索,我发现不鼓励使用
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)))

另外,我知道声明变量的唯一方法是使用
和localvars
关键字。一开始在一个块中定义所有变量不是很不实际吗?或者我遗漏了一些关键点吗?

我自己也在学习Clojure,所以不要把这当作导师的建议,而是同学们的建议

Clojure是一种函数式编程语言。 函数式编程意味着没有循环,没有变量,没有副作用。如果你曾经偏离这三条规则,你需要很好的理由来这么做,而有效的理由是非常罕见的

你显然是一个非常熟练的程序员,所以看看这些信息 你应该对功能设计和面向对象设计有更多的了解

另外,我建议看一些clojure代码,这里是一个托管在 github.com是clojure screencast教程的一部分

可在此处找到该代码的screencast教程,但它不是免费的:

(无论如何,我与peepcode.com没有任何关联)


祝你和Clojure好运

您正在编写的是具有类似lisp语法的C代码(无意冒犯)。通过你不做的事情来定义一种风格是非常有定义性的,但是如果你不知道“好吧,那么还有什么其他的呢?”

顺便说一下,我不知道指示器应该做什么

这就是我处理这个问题的方法:

  • 问题有两个部分:找到要读取的字符数,然后读取那么多字符。因此,我将编写两个函数:
    readcount
    readitem
    ,后者使用前者

    (defn read-count [stream] ;; todo ) (defn read-item [stream] ;; todo )
  • 在Clojure中,通常最好使用
    loop
    recur
    来处理循环
    loop
    还绑定变量,如
    let
    acc
    旨在累加读取的项目,但请注意,它不是就地修改,而是在每次迭代中重新绑定

    (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
  • 现在我们只需要
    读取计数
    函数。它使用类似的循环

    (defn read-count [stream] (loop [count 0] (let [c (.read stream)] (if (= c ":") count (recur (+ (* count 10) (Integer/parseInt c))))))) (定义读取计数[流] (循环[计数0] (让[c(.read stream)] (如果(=c): 计数 (重复(+*计数10) (整数/parseInt c(()()()())))
  • 在REPL、debug和refactor上测试它。
    .read
    真的返回字符吗?有没有更好的方法来解析整数


  • 我没有测试过这一点,我对Clojure既没有任何经验也没有深刻的了解(我主要使用Common Lisp),这让我有点为难,但我认为它展示了如何以“lispy”的方式处理此类问题。请注意,我是如何不考虑声明或修改变量的。

    Idomatic Clojure真的很适合处理序列。在C语言中,我倾向于用变量或者多次改变变量的状态来思考问题。在Clojure中,我是按照顺序思考的。在本例中,我将把问题分为三个抽象层:

    
    (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)))
    
    • 将流转换为字节序列
    • 将字节序列转换为字符序列
    • 将字符序列转换为字符串序列
    流到字节:

    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:我现在不在回复中,所以请编辑以修复任何错误:)

    我想这次聚会晚了一点,但如果您只是将字符串作为一个字符序列来处理,并使用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")
    
    摘要:

    • 将丑陋的、有副作用的输入流转换成一个惰性的字符序列,这样我们就可以在这个操作的其余部分将它假装成一个字符串。如您所见,实际上从流中读取的字符数不超过计算结果所需的字符数
    • 将字符串分为两部分:第一个冒号前的前半个字符,以及剩余的后半个字符
    • 使用destructuring将这些部分绑定到名为
      之前的局部变量
      之后的局部变量
      ,并通过将其绑定到名为
      冒号
      的未使用局部变量来进行描述,从而在执行时去掉
    • 在之前读取
      ,以获取其数值
    • 之后从
      中提取那么多字符,并使用
      (apply str)

    Svante的回答是如何使用Clojure编写循环ish代码的一个很好的例子;我希望我的是一个组装内置函数的好例子,这样它们就可以满足您的需要。当然,这两种方法都使C解决方案看起来“非常简单”

    如果我正确理解了你的建议,我应该通过尽可能多地将其组合成单独的函数来解决问题,对吗?我不会说尽可能多,而是尽可能明智——你找出你可以命名的概念,然后将它们封装在名称后面。然而,这只是上面的一个小方面。你总是能给出这么好的功能性答案+1选择流而不是字符串的决定也会使函数更加复杂
    (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")