Сегодня я немного поигрался с 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 Марка Нидхэма в блоге Марка Нидхэма . |