Я изучаю Clojure и начал с копирования функциональности программы Python, которая создавала бы геномные последовательности, следуя (чрезвычайно простой) скрытой марковской модели.
В начале я придерживался своего известного способа последовательного программирования и часто использовал ключевое слово def, тем самым решая проблему с кучей побочных эффектов, пиная почти все концепции Clojure прямо в задницу. (хотя это сработало, как предполагалось)
Затем я попытался преобразовать его в более функциональный способ, используя loop, recur, atom и так далее. Теперь, когда я запускаю, я получаю ArityException, но я не могу прочитать сообщение об ошибке таким образом, который показывает мне, даже какая функция его выдает.
(defn create-model [name pA pC pG pT pSwitch]
; converts propabilities to cumulative prop's and returns a char
(with-meta
(fn []
(let [x (rand)]
(if (<= x pA)
\A
(if (<= x (+ pA pC))
\C
(if (<= x (+ pA pC pG))
\G
\T))))) ; the function object
{:p-switch pSwitch :name name})) ; the metadata, used to change model
(defn create-genome [n]
; adds random chars from a model to a string and switches models randomly
(let [models [(create-model "std" 0.25 0.25 0.25 0.25 0.02) ; standard model, equal props
(create-model "cpg" 0.1 0.4 0.4 0.1 0.04)] ; cpg model
islands (atom 0) ; island counter
m (atom 0)] ; model index
(loop [result (str)]
(let [model (nth models @m)]
(when (< (rand) (:p-switch (meta model))) ; random says "switch model!"
; (swap! m #(mod (inc @m) 2)) ; swap model used in next iteration
(swap! m #(mod (inc %) 2)) ; EDIT: correction
(if (= @m 1) ; on switch to model 1, increase island counter
; (swap! islands #(inc @islands)))) ; EDIT: my try, with error
(swap! islands inc)))) ; EDIT: correction
(if (< (count result) n) ; repeat until result reaches length n
(recur (format "%s%c" result (model)))
result)))))
Запуск работает, но вызов (create-genome 1000) приводит к
ArityException Wrong number of args (1) passed to: user/create-genome/fn--772 clojure.lang.AFn.throwArity (AFn.java:429)
Мои вопросы:
- (очевидно) что я делаю не так?
- как именно я должен понимать сообщение об ошибке?
Информация, которую я буду рад получить
- как можно улучшить код (так, чтобы clojure-newb мог его понять)? Также разные парадигмы - я благодарен за предложения.
- Почему мне нужно ставить знак решетки # перед формами, которые я использую для изменения состояний атомов? Я видел это в примере, без него функция не будет вычисляться, но я не понимаю :)