Clojure 递归和惰性序列

4

好的,我在这个问题上有些困惑,我是否可以通过下面代码中的部分实现我的目标:

(recur (conj (get-links (first links)) (rest links))))

get-links函数返回一系列URL,这些URL将被传递到initial process-links函数中,然后应该进行递归处理。

我输入的第一个链接有效,但是在尝试将一个序列连接到另一个序列时出现了以下错误。

"Clojure.lang.LazySeq@xxxxxxx"

我在想,这是否会引用生成“剩余”(剩余链接)未评估序列的指令?

(defn process-links
  [links]
  (if (not (empty? links))
    (do
      (if (not (is-working (first links)))
        (do
          (println (str (first links) " is not working"))
          (recur (rest links)))
        (do
          (println (str (first links) " is working"))
          (recur (conj (get-links (first links)) (rest links))))))))

如果我的方法完全错误,请告诉我。

3
有关代码的一些提示。您不应该写(not (empty? ...)),因为empty?的实现是(not (seq...))。所以您基本上在写(not (not (seq ...)))。只需编写(seq ...)即可,这是常见的模式。我认为您不必要这样做(println (str ...)),在大多数情况下,只需执行(println...)即可。使用(if-not)而不是(if (not ...))。最顶层的if没有'else'部分,在这种情况下请使用when函数。第一个'do'函数也可以被抛弃(特别是使用'when'时,'when'宏总是添加一个'do')。希望这有所帮助。 - nickik
谢谢你的建议,看起来很有道理 :) - Dale
2个回答

7

conj将一个项目添加到集合中。在两个集合上使用它会创建一个嵌套结构。您可能希望使用concat连接这两个序列。

举个例子:

user> (conj [1 2 3] [4 5 6])
[1 2 3 [4 5 6]]
user> (concat [1 2 3] [4 5 6])
(1 2 3 4 5 6)

1
好的,搞定了!又发现了一个我不知道的函数!必须交换我的(get-links(first links))和(rest links),但这似乎解决了问题。谢谢! - Dale

1
关于"Clojure.lang.LazySeq@xxxxxxx"的问题:
问题在这段代码里:
(println (str (first links) " is working"))

在这里,您使用字符串连接函数str(first links)(在此情况下不是字符串)和" is working"(是一个字符串)粘合在一起。 str对于非字符串参数会发生什么?它会调用其上的.toString方法。对于Clojure数据,.toString做了什么?并不总是你想要的。

解决方案是使用pr函数族。 pr以clojure reader可以识别的方式将Clojure数据写入流中。以下是如何重写上面代码片段的两个示例:

(do (pr (first links))
    (println " is working"))

;; Sligtly less efficient since a string must be created
(println (pr-str (first links)) "is working")

请注意,如果您向println提供多个参数,则它将在它们之间打印所有项目并用空格分隔。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接