Я хочу применить серию тестов в своем списке и убедиться, что все тесты пройдены. Есть ли функция, аналогичная «andmap» в Clojure?
Есть ли функция, аналогичная andmap в clojure?
Ответы (4)
Вы можете использовать every?
:
user=> (every? string? '("hi" 1))
false
Вот документация по every?
.
Clojure 1.3 добавит every-pred (и соответствующий some-fn для версии "or").
clojure.core/every-pred ([p] [p1 p2] [p1 p2 p3] [p1 p2 p3 и ps])
Принимает набор предикатов и возвращает функцию f, которая возвращает истину, если все составляющие ее предикаты возвращают логическое значение истинности для всех ее аргументов, в противном случае она возвращает ложь. Обратите внимание, что f является коротким замыканием в том смысле, что он останавливает выполнение на первом аргументе, который вызывает логический ложный результат для исходных предикатов.
Наивная реализация может быть:
(defn every-pred [& preds] (fn [& args] (every? #(every? % args) preds)))
но фактическая реализация будет иметь лучшую производительность.
Я написал andmap
как макрос, который принимает предикаты в качестве аргументов и создает функцию, которая «обертывает and
вокруг предикатов», т.е.
(andmap integer? odd?)
==>
(fn [x] (and (integer? x)
(odd? x)))
(он расширяется не до точно этого, но расширяется до чего-то эквивалентного этому)
Это имеет то преимущество, что оно сокращает предикаты, поэтому вы можете написать
(every? (andmap integer? odd?) [1 3 "a string"])
без получения исключения во время выполнения, как вы могли бы получить с помощью Ответ Артура.
Вот определение andmap
:
(defmacro andmap ([] `(fn [& x#] true)) ([p & ps] `(fn [& x#] (and (apply ~p x#) (apply (andmap ~@ps) x#)))))
Также можно определить andmap
как функцию, которая также замыкает свои предикаты из-за лени:
(defn andmap [& ps] (fn [& x] (every? true? (map (fn [p] (apply p x)) ps))))
Предикаты andmap могут принимать произвольное количество аргументов, поэтому можно написать
(map (andmap #(and (integer? %1)
(integer? %2))
#(and (odd? %1)
(even? %2))
<)
[1 3 9]
[2 6 "string"])
который оценивается как (true true false)
.
every?
спросит: «Возвращает ли эта функция true для каждого члена последовательности», что близко к тому, о чем, как мне кажется, вы просите. Улучшение every?
будет принимать список функций и спрашивать: «Все ли эти предикаты верны для каждого члена этой последовательности».
Вот первая попытка:
(defn andmap? [data tests]
(every? true? (for [d data, f tests]
(f d))))
user> (andmap? '(2 4 8) [even? pos?])
true
user> (andmap? '(2 4 8) [even? odd?])
false