Clojure For Comprehension example

2019-02-07 08:36发布

I am using docjure and it needs a column map for its select-columns function. I would like to grab all my columns without having to specify it manually. How do I generate the following as a lazy infinite vector sequence [:A :B :C :D :E ... :AA :AB :AC .... :ZZ ... :XFD]?

7条回答
可以哭但决不认输i
2楼-- · 2019-02-07 09:23

I think this may be the kind of thing you were looking for (if not, well, at least it is what I thought the "correct" answer should be ;o).

(defn stream [seed]
  (defn helper [slow]
    (concat (map #(str (first slow) %) seed) (lazy-seq (helper (rest slow)))))
  (declare delayed)
  (let [slow (cons "" (lazy-seq delayed))]
    (def delayed (helper slow))
    delayed))

(take 25 (stream ["a" "b" "c"]))
("a" "b" "c" "aa" "ab" "ac" "ba" "bb" "bc" "ca" "cb" "cc" "aaa" "aab" "aac" "aba" "abb" "abc" "aca" "acb" "acc" "baa" "bab" "bac" "bba")

Code in git. I suspect I am abusing def horribly, but it works.

The idea is pretty simple: I take the output from the sequence and feed it back on itself. For each value in the output (which is also the input), I generate a new output by appending each of the letters in the seed sequence. Since this is circular it just keeps on going (there's an initial "" which is in the input, but not the output, that helps avoid creating something from nothing).

The process of feeding the output into the input is called "tying the knot" in a fairly famous paper for Haskell. But it's harder to do in Clojure because it's an eager language (and even lazy sequences aren't "lazy enough") - the only solution I could find was that mess with def (I suspect someone might do better with delay and force, but I had no luck).

And maybe it could even be written as a map?

[updated 2012-07-19 with more compact code]

Related question with much better code in an answer at Tying the knot in Clojure: circular references without (explicit, ugly) mutation? (it's the same idea as jneira's answer).

For completeness, here's the final version using iterate:

(defn stream [seed]
  (defn helper [slow] (mapcat (fn [c] (map #(str c %) seed)) slow))
  (apply concat (iterate helper seed)))
查看更多
登录 后发表回答