Сегодня я немного поигрался с Clojure, готовясь к выступлению на следующей неделе, и обнаружил, что пишу следующий код, чтобы применить ту же функцию к трем различным оценкам:
|
1
2
3
4
5
6
7
|
(defn log2 [n] (/ (Math/log n) (Math/log 2))) (defn score-item [n] (if (= n 0) 0 (log2 n))) (+ (score-item 12) (score-item 13) (score-item 5)) 9.60733031374961 |
Я забыл о сворачивании коллекции, но быстро вспомнил, что могу добиться того же результата с помощью следующего кода:
|
1
|
(reduce #(+ %1 (score-item %2)) 0 [12 13 5]) 9.60733031374961 |
Дополнительное преимущество заключается в том, что если я хочу добавить 4-й счет к миксу, все, что мне нужно сделать, это добавить его в конец вектора:
|
1
|
(reduce #(+ %1 (score-item %2)) 0 [12 13 5 6]) 12.192292814470767 |
Тем не менее, в то время как Googling, чтобы напомнить себе о порядке аргументов для сокращения, я продолжал сталкиваться со статьями и документацией о редукторах, о которых я слышал, но никогда не использовал.
Как я понимаю, они используются для повышения производительности и упрощения компоновки функций по сравнению с коллекциями, поэтому я не уверен, насколько они будут полезны для меня, но я решил попробовать.
Нашим первым шагом является введение пространства имен в область видимости:
|
1
|
(require ' [ clojure.core.reducers :as r]) |
Теперь мы можем вычислить тот же результат, используя функцию Reduce:
|
1
|
(r/reduce #(+ %1 (score-item %2)) 0 [12 13 5 6]) 12.192292814470767 |
Пока что так идентично. Если бы мы хотели рассчитать отдельные оценки, а затем отфильтровать их ниже определенного порога, код работал бы немного иначе:
|
1
2
3
4
5
6
7
|
(->>[12 13 5 6] (map score-item) (filter #(> % 3))) (3.5849625007211565 3.700439718141092) (->> [12 13 5 6] (r/map score-item) (r/filter #(> % 3))) #object [ clojure.core.reducers$folder$reify__19192 0x5d0edf21 " clojure.core.reducers$folder$reify__19192@5d0edf21 "] |
Вместо того, чтобы давать нам вектор баллов, версия редукторов возвращает редуктор, который может переходить в уменьшение или свертывание, если мы хотим получить накопленный результат или если мы хотим вывести коллекцию. В этом случае мы хотим последнее:
|
1
2
3
4
|
(->> [12 13 5 6] (r/map score-item) (r/filter #(> % 3)) (into [])) (3.5849625007211565 3.700439718141092) |
Я не думаю, что редкие редукторы обеспечат здесь значительное улучшение скорости, но нам нужно использовать функцию сгиба, если мы хотим, чтобы обработка коллекции выполнялась параллельно.
Один на следующий раз!
| Ссылка: | Clojure: Первые шаги с редукторами от нашего партнера JCG Марка Нидхэма в блоге Марка Нидхэма . |