The value of :selector-fn
in the grammar map is used for selecting a rule.
The function takes three arguments, the current grammar, the selected for rule head and a vector of valid rule bodies.
It returns a new grammar with the selected rule body assoc
:ed under the :selected
key:
(defn selector-fn [grammar head bodies]
(assoc grammar :selected (rand-nth bodies)))
The default selector function above just picks a rule at random.
Note that you can use the :data
key in the grammar to store metadata about the rules.
For example, you can save the rule id of every rule selected and prefer those that have been selected least:
(grotesque/set-selector
grammar
(fn [old-grammar head bodies]
(let [selected (->> bodies
(sort-by #(-> old-grammar :data :times-selected ((:id %))))
first)]
(-> old-grammar
(update-in [:data :times-selected (:id selected)] #(if (nil? %) 1 (inc %)))
(assoc :selected selected)))))
If you wanted to e.g. have a character’s name appear in the text,
you could generate a rule for the character that has their name on it.
But you could also make a selector that does the job for you:
(-> grammar
(grotesque/set-selector (fn [old-grammar head bodies]
(let [names (-> old-grammar :data :names)]
(if (contains? names head)
(assoc old-grammar :selected {:id :meta, :text [(get names head)]})
(assoc old-grammar :selected (rand-nth bodies))))))
(assoc-in [:data :names] {:hero "Ilsa", :villain "Rodric", :donor "Mustiff"}))
Note that rule heads are keywords without dots.
So :story
is a valid head but :dance.time
is not.
This is because it would interfere with modifiers, a planned feature.
Can you improve this documentation?Edit on GitHub
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close