Есть ли функция, аналогичная andmap в clojure?

Я хочу применить серию тестов в своем списке и убедиться, что все тесты пройдены. Есть ли функция, аналогичная «andmap» в Clojure?


person unj2    schedule 30.07.2009    source источник
comment
не могли бы вы добавить ввод и вывод emaple?   -  person Arthur Ulfeldt    schedule 01.08.2009


Ответы (4)


Вы можете использовать every?:

user=> (every? string? '("hi" 1))
false

Вот документация по every?.

person Pinochle    schedule 30.07.2009

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)))

но фактическая реализация будет иметь лучшую производительность.

person miner49r    schedule 04.04.2011

Я написал 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).

person Jonas    schedule 31.07.2009

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
person Arthur Ulfeldt    schedule 30.07.2009