2 ms·
So, worried that I was being overly-negative, I thought I'd offer something of substance. If you wanted to separate the Markov bits from the string bits, you co
by thom 11y ago
So, worried that I was being overly-negative, I thought I'd offer something of substance. If you wanted to separate the Markov bits from the string bits, you could do it thusly:
(defn markov-chain [coll]
(let [adjacencies (partition 2 1 coll)
initial-chain {::start [(first coll)]
(last coll) [::end]}]
(reduce
(fn [chain [predecessor successor]]
(assoc chain predecessor (conj (get chain predecessor []) successor)))
initial-chain
adjacencies)))
(defn successor [chain item]
(rand-nth (get chain item)))
(defn follow-chain [chain]
(->> ::start
(iterate (partial successor chain))
(remove #{::start ::end})
(take-while some?)))
(defn sentences [text]
(clojure.string/split text #"\."))
(defn words [sentence]
(remove empty? (clojure.string/split sentence #"\s+")))
(defn markov-text [text]
(->> text
sentences
(map words)
(map markov-chain)
(apply merge-with into)))
(defn render-sentence [words]
(str (clojure.string/join " " words) \.))
(defn sentence [chain]
(render-sentence (follow-chain chain)))
I'm not saying this is in any way strictly better, but it leaves you with abstractions that can be reused, and text-specific stuff in one place that could be a separate namespace. This is what I'd look for in a code-review of a refactoring like this - not just neatness, but making abstractions explicit and separate, naming as many things as possible, etc etc.