在REPL

时间:2015-10-31 14:18:26

标签: clojure lazy-evaluation lazy-sequences

我正在尝试在REPL中实现一个懒惰的序列(应该生成一个单独的字符串),没有运气。原始代码工作正常:

(def word_list ["alpha" "beta" "gamma" "beta" "alpha" "alpha" "beta" "beta" "beta"])
(def word_string (reduce str (interpose " " word_list))); 
word_string ; "alpha beta gamma beta alpha alpha beta beta beta"

但是我不想单独留下足够好的东西,我想知道还有什么可行,并尝试删除reduce,认为str可能会产生同样的效果。它没有......

(def word_string (str (interpose " " word_list)))
word_string ; "clojure.lang.LazySeq@304a9790"

我尝试了显而易见的,再次使用reduce,但这也无效。有another question关于实现看似有希望的懒惰序列,但我尝试过的任何工作都没有:

(reduce str word_string)   ; "clojure.lang.LazySeq@304a9790"
(apply str word_string)    ; "clojure.lang.LazySeq@304a9790"
(println word_string)      ; "clojure.lang.LazySeq@304a9790"
(apply list word_string)   ; [\c \l \o \j \u \r \e \. \l \a \n \g \. \L \a \z \y...]
(vec word_string)          ; [\c \l \o \j \u \r \e \. \l \a \n \g \. \L \a \z \y...]
(apply list word_string)   ; (\c \l \o \j \u \r \e \. \l \a \n \g \. \L \a \z \y...)
(take 100 word_string)     ; (\c \l \o \j \u \r \e \. \l \a \n \g \. \L \a \z \y...)

事实上,某些变体,给了我“clojure.lang.LazySeq”中的字符也让我担心 - 我是否以某种方式丢失了实际的字符串值,而我的引用只是有价值“clojure.lang.LazySeq”?如果没有,我该如何实现价值?

澄清一下:鉴于word_string被分配给一个懒惰的序列,我怎么能意识到它?像(realize word_string)这样的东西,比如,如果存在的话。

更新:根据已接受的答案以及str的工作原理,我发现可以获取实际的序列值,而不仅仅是其名称:

(reduce str "" word_string) ; "alpha beta gamma beta alpha alpha beta beta beta"

是的,这是可怕的代码。 :)我只是想了解发生了什么,为什么它会破坏,以及实际值是否仍然那里

2 个答案:

答案 0 :(得分:4)

你想要的是:

(def word_string (apply str (interpose " " word_list)))

查看str的文档:

  

如果没有args,则返回空字符串。使用一个arg x,返回
    x.toString()。 (str nil)返回空字符串。超过
    一个arg,返回args的str值的串联。

所以你在序列上调用.toString,生成该表示而不是将str作为参数应用于序列的元素。

顺便说一下,做你想做的事的更惯用的方式是:

(clojure.string/join " " word_list)

此外,字符串不是惰性序列。 interpose会返回一个懒惰的序列,而您正在调用.toString

答案 1 :(得分:1)

你不需要做任何特别的事情来实现clojure中的懒惰seq,你只需在seq预期的任何地方使用它。

user=> (def word-list ["alpha" "beta" "gamma" "beta" "alpha" "alpha" "beta" "beta" "beta"])
#'user/word-list
user=> (def should-be-a-seq (interpose " " word_list))
#'user/should-be-a-seq
user=> (class should-be-a-seq)
clojure.lang.LazySeq

所以我们有一个seq,如果我在任何情况下使用它来遍历seq中的所有值,它将最终完全实现。 e.g。

user=> (seq should-be-a-seq)
("alpha" " " "beta" " " "gamma" " " "beta" " " "alpha" " " "alpha" " " "beta" " " "beta" " " "beta")

它仍然是一个seq,实际上它仍然是以前的对象。

user=> (str should-be-a-seq)
"clojure.lang.LazySeq@304a9790"

正如Diego Basch所说,调用str就像调用.toString一样,对于LazySeq方法来说,它显然只是继承自Object的默认.toString。

因为它是一个seq,你可以像任何seq一样使用它,无论它是否已经完全实现。 e.g。

user=> (apply str should-be-a-seq)
"alpha beta gamma beta alpha alpha beta beta beta"
user=> (reduce str should-be-a-seq)
"alpha beta gamma beta alpha alpha beta beta beta"
user=> (str/join should-be-a-seq)
"alpha beta gamma beta alpha alpha beta beta beta"
user=> (str/join (map #(.toUpperCase %) should-be-a-seq))
"ALPHA BETA GAMMA BETA ALPHA ALPHA BETA BETA BETA"