Fork me on GitHub
#beginners
<
2019-09-15
>
Christian Barraza06:09:24

Hey everyone! Working through Brave and True so I can help with a particular project- came across a suggestion to try and re-implement the 'comp' function

Christian Barraza06:09:03

Anyways, here is my code, which works with two arguments, but no more. And I'm really struggling to understand why:

Christian Barraza06:09:51

(defn my-comp [f & g] (fn [& args] (f (if (= (count g) 1) (apply (first g) args) (apply my-comp g)))))

Christian Barraza06:09:38

I keep getting "Unhandled java.long.ClassCastException clojure_noob.core$my_comp$fn__5806 cannot be cast to java.lang.Number" when I try to call ((my-comp inc inc *) 2 3)

jumar06:09:52

@UN67GMG81 you're trying to apply pass the result of (apply my-comp g) as a first arg to f which is inc in your case; inc expects a number but the result (apply my-comp g) is a function => you need to wrap it in extra parenthesis and pass args as well - In your particular case something like this:

(defn my-comp
  [f & g]
  (fn [& args]
    (f (if (= (count g) 1)
         (apply (first g) args)
         (apply (apply my-comp g) args)))))
((my-comp inc inc *) 2 3)
;; => 8

jumar06:09:39

But I guess it's better to look at the source of clojure.core/comp

Christian Barraza14:09:35

@jumar Thank you very much.

Christian Barraza19:09:42

@jumar out of curiosity then, am I missing the order in which things happen? For some reason I thought the (apply my-comp g) would resolve to its fullest first, passing (inc ) to my-comp, and then you'd end up with (inc (inc (apply args))). Is it resolving f(apply my-comp g) before it fully recurs my-comp?

seancorfield21:09:07

@UN67GMG81 The problem is that the result of my-comp is a function which means that (apply my-comp g) is going to return a function -- and then you're trying to call f on that. Since f is inc from that first call, it doesn't really matter what (apply my-comp g) evaluates to beyond it being (fn [& args] ,,,) -- you can't increment that function.

seancorfield21:09:55

Also, (my-comp inc) will fail whereas (comp inc) works, so that's another case to think about.

seancorfield21:09:38

Similarly, (my-comp) fails but (comp) returns the identity function.

sova-soars-the-sora13:09:19

I'm trying to filter a Vector of Maps [{v} {q} {r}] by nested values. I'm having trouble smashing every-pred and get-in

sova-soars-the-sora13:09:44

[{:english "Go to the park at 3pm."
	:bunsetsu { :jar1 "3pm"  :lid1 "に" :sense1 "ni-time"
	:jar "the park" :lid2 "に" :sense2 "ni-destination"
        :verb "go" :verbsense "travel-verb"} ...more entries]

sova-soars-the-sora13:09:12

I'd like to grab all the maps from this vector where [:bunsetsu :lid1] and [:bunsetsu :lid2] are members of a known-list. i'm having trouble figuring out how to filter on nested elements.

sova-soars-the-sora14:09:01

Maybe I can store it more intelligently. I have 2 vital pieces of info in each map. Can I index map entries with 2 values o.O?

sova-soars-the-sora14:09:03

Using get-in, I need to provide a numerical index, like 1 or 2, but a lot of the examples i see using filter against a vector of maps doesn't have this

sova-soars-the-sora15:09:55

I do a for loop and I end up with lots of extra nils... easy way to get rid?

sova-soars-the-sora15:09:18

(nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil 5 nil nil nil nil nil nil 7 nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil)

sova-soars-the-sora15:09:48

For loop probably not the best solution but i'm not having much success trying to do filter with get-in

mfikes15:09:01

@sova Maybe something along these lines?

(let [v    [{:a 1 :b {:c "x"}}
            {:a 2 :b {:c "y"}} 
            {:a 3 :b {:c "z"}}]
      pred (fn [m] 
             (#{"x" "z"} (get-in m [:b :c])))]
  (filter pred v))

sova-soars-the-sora15:09:43

thank you! i was missing the map from the predicate. can you help me understand why the predicate needs a map?

sova-soars-the-sora15:09:07

can the predicate be multiple lines like that linked with (and) ?

sova-soars-the-sora15:09:48

(let [v    [{:a 1 :b {:c "x" :d "e"}}
            {:a 2 :b {:c "y" :d "f" }} 
            {:a 3 :b {:c "z" :d "g"}}]
      pred (fn [m] 
             (and (#{"x" "z"} (get-in m [:b :c]))
           (#{"e" "f" "g"} (get-in m [:b :d]))))]
  (filter pred v))

mfikes16:09:11

@sova filter looks at each item in the collection, applying the supplied pred to to each in order to determine whether to include it in the output. In this case, the items in the vector are maps. The implementation of pred can be anything: For this problem, it will be passed a single map, and it can look inside that map to decide whether it should be included in the output, and it can also apply arbitrary Boolean logic (using and, or, not etc.)

sova-soars-the-sora16:09:52

wonderful. thanks so much @mfikes you saved me time, energy. Amazing. I can filter this thing down so cleanly now. Much appreciated. I had seen this set pattern #{} a little bit on Stack Overflow and it turns out to be super duper useful!

gerred16:09:08

it would be fun to write a solver that takes one data structure shape and attempts to come up with the most efficient transformations to get to the other, especially if it could use transducers.

gerred16:09:14

even if it threw up it's hands a lot of the time.

andy.fingerhut17:09:02

I haven't even used it, but have heard descriptions of Specter that it has some of that inside, or at least some kind of internal run-time optimizations.

henrik18:09:15

For complicated stuff, specter can be a lot faster than the core libs due to the internal optimizations it does. For the easy stuff, it almost never is. It’ll never make a faster get or assoc for example.

Christian Barraza19:09:42

@jumar out of curiosity then, am I missing the order in which things happen? For some reason I thought the (apply my-comp g) would resolve to its fullest first, passing (inc ) to my-comp, and then you'd end up with (inc (inc (apply args))). Is it resolving f(apply my-comp g) before it fully recurs my-comp?