On Fri, Aug 14, 2020 at 9:05 AM Oleksandr Shulgin < oleksandr.shul...@zalando.de> wrote:
> On Fri, Aug 14, 2020 at 7:51 AM Alexandre Almosni < > alexandre.almo...@gmail.com> wrote: > >> Maybe your objects could be defined by a map containing functions and >> objects. >> >> So exampleAndList = {:fn and, :coll [a b c]} >> >> >> And then eval goes through your objects recursively, using >> >> (def eval [o] >> (apply (:fn o) (map eval (:coll o)))) >> >> - with a special case that if o is not a map but say a Boolean you just >> return itself >> > > A slight problem with that approach is that clojure.core/and is not a > function, but a macro: the reason being is that it stops evaluating forms > as soon as it hits a falsey value (similar for "or"). > A smart implementation of And/OrList would like to short-circuit as well I > guess, so you'll need to express that somehow. > > Of the clojure.core library that property is satisfied by transducers: > https://clojure.org/reference/transducers#_early_termination > I came up with the following: ;; and-transducer with early termination: (defn xand [rf] (fn ([] (rf)) ([res] (rf res)) ([res inp] (if inp (rf res inp) (reduced inp))))) ;; reducing function implementing and: (defn andr ([] true) ([i] i) ([r i] (and r i))) ;; noisy variant of get: (defn noisy-get ([k] (fn [m] (noisy-get m k))) ([m k] (println "noisy-get" m k) (get m k))) ;; all in action: user> (def xf (comp (map (noisy-get :data)) xand)) #'user/xf user> (transduce xf andr [{:data 1} {:data false} {:no-data 3}]) noisy-get {:data 1} :data noisy-get {:data false} :data false user> (transduce xf andr [{:data 1} {:data 2} {:no-data 3} {:data 4}]) noisy-get {:data 1} :data noisy-get {:data 2} :data noisy-get {:no-data 3} :data nil user> (transduce xf andr [{:data 1} {:data 2} {:data 3} {:data 4}]) noisy-get {:data 1} :data noisy-get {:data 2} :data noisy-get {:data 3} :data noisy-get {:data 4} :data 4 It does feel a bit redundant to have the reducing function on top of a transducer that accomplishes mostly the same, but I haven't found a way to make it shorter. Cheers, -- Alex > On 14 Aug 2020, at 02:24, Jack Park <jackp...@topicquests.org> wrote: >> >> >> The problem: >> >> In Java, I have an interface *IInferrable* which is basically boolean >> eval(); >> >> Any Java object which extends IInferrable, no matter what it is, will >> answer to eval() and return a boolean. >> The idea lies at the heart of an inference engine. >> >> But, I also define a class *AndList* which implements IInferrable and >> extends java.util.ArrayList<Inferrable> >> >> So, AndList, and its sibling OrList behave just like a List object, but >> also will answer to eval() by running the collection and dealing with what >> each element returns when it, too, is eval()'d. >> >> I'd really love to discover how to pull that off in Clojure. >> >> -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/clojure/CACACo5TDpMg_CEhE2ytwZv9R1L3%3DifayFLYTs6KC80vON59hiw%40mail.gmail.com.