【问题标题】:Realizing a Clojure lazy sequence (string) in the REPL在 REPL 中实现 Clojure 惰性序列(字符串)
【发布时间】:2015-10-31 14:18:25
【问题描述】:

我试图在 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"

是的,这是一个糟糕的代码。 :) 我只是想了解发生了什么,为什么会中断,以及实际值是否仍然存在

【问题讨论】:

    标签: clojure lazy-evaluation lazy-sequences


    【解决方案1】:

    你想要的是:

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

    str的文档:

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

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

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

    (clojure.string/join " " word_list)
    

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

    【讨论】:

    • 我想我并不清楚我的问题 - 我能够使用 reduce 将完全实现的字符串分配给 word_string,尽管 apply 可能会更好。但是鉴于word_string 被分配给了一个惰性序列,我该如何实现呢?我要对word_string 应用什么操作,比如(realize word_string)
    • 我想你很困惑:word_string 的第二个赋值不是惰性序列;它是一个字符串,它是在惰性序列上调用 .toString 的结果。惰性序列的字符串表示不是很有用,也不是您想要的。看到这个问题:stackoverflow.com/questions/7946219/…
    • 是的,我确实很困惑。 :) Clojure 有很多奇怪、错误、不直观的方面、惰性序列等,我仍在努力理解这些方面。但是,我想我看到了在这种情况下发生了什么, str 并没有按照我最初的想法做。谢谢。
    【解决方案2】:

    你不需要做任何特别的事情来实现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
    

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

    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 一样使用它,无论它之前是否已完全实现。例如

    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"
    

    【讨论】:

    • 如果你像我一样使用str,虽然(def should-be-a-seq (str (interpose " " word_list))),它的行为会有所不同。我是否应该使用str当然是一个有效的问题,但我试图了解分配给(def word_string (str (interpose " " word_list)))的内容,以及如何操作它。
    • @JohnC str 返回一个字符串。在这种情况下,这不是您想要的字符串。
    猜你喜欢
    • 2011-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-26
    相关资源
    最近更新 更多