Fork me on GitHub
#beginners
<
2018-11-04
>
Michael Stokley02:11:11

clojure-scratch.core> (defn curried-add [x] (fn [y] (+ x y)))
#'clojure-scratch.core/curried-add
clojure-scratch.core> (-> 1 (curried-add 1))
ArityException Wrong number of args (2) passed to: core/curried-add  clojure.lang.AFn.throwArity (AFn.java:429)
clojure-scratch.core> (-> 1 ((curried-add 1)))
2

Michael Stokley02:11:27

why do I need the extra set of parens?

Michael Stokley02:11:43

the expression (curried-add 1) is already a function of arity 1

hiredman02:11:40

-> is a simple transformation of syntax, it doesn't know anything about semantics

hiredman02:11:20

it transforms (-> x (y)) into (y x) regardless of what y or x are

hiredman02:11:12

so (-> 1 (x 1)) is (x 1 1), and if x is a function that only takes 1 argument, that is going to throw an error when it runs

Michael Stokley02:11:39

oh, i thought (-> x (y)) would be something like (apply (y) x)

hiredman02:11:57

user=> (macroexpand '(-> 1 (curried-add 1)))
(curried-add 1 1)
user=> 

Michael Stokley03:11:00

oh, maybe my mistake was thinking that the expression (curried-add 1) would evaluate to a unary function before being rearranged by ->

Michael Stokley03:11:16

but it's done in the opposite order

seancorfield03:11:26

Correct. Macros apply first. Then code is evaluated.

seancorfield03:11:59

(because macros take "code as data" and produce "code as data" -- and then that "data" is read (into code) and evaluated)

Michael Stokley03:11:03

is there a function, then, like (function-version-of-thread-first-macro val f1 f2 f3) that produces the equivalent of (f3 (f2 (f1 val)))?

seancorfield03:11:21

With -> at the beginning, you mean? Yes.

seancorfield03:11:44

Ah, to your edited question: no.

seancorfield03:11:11

The closest would be (reduce (fn [v f] (f v)) val [f1 f2 f3]))

joshkh11:11:21

how do i use private github repos with deps.edn? i'm getting the following error: `Cloning: [email protected]:myorg/myrepo.git Error building classpath. [email protected]:myorg/myrepo.git: Auth fail`

joshkh11:11:21

whoops, ssh-agent problem 🙂

rgdelato19:11:02

is there a built-in function to check if a value exists in a list/vector?

rgdelato19:11:02

(some #(= % [i j]) my-list) works, but just wondered if something like contains? existed for values instead of keys

didibus21:11:54

You can use .contains. Since Java defines a value based contains (as opposed to the key based one of clojure.core) for all Collection types.

didibus21:11:28

Won't work in ClojureScript though, for obvious reasons.

enforser19:11:05

not that I'm aware of! I generally use the some method, but have wondered if it's better to cast the vector/list into a set. (contains? (set my-list) element)

mfikes19:11:15

Another somewhat related approach is to employ .indexOf, perhaps combined with nat-int?

👍 1
mfikes19:11:09

This will work in Clojure, and is also guaranteed to work in ClojureScript: https://clojurescript.org/reference/javascript-api#indexOf

didibus21:11:39

Cool, for hybrid code, this is pretty nice.

kenj20:11:11

Is there an idiomatic way to do a filter w/ multiple functions+accumulators such that you can compute several unrelated values via a single iteration? I can’t think of a way to do it without using a vector or dict as the accumulator which seems not great to me.

didibus23:11:08

I'd have a look at transjuxt from https://github.com/cgrand/xforms It lets you do this with transducers. You could also use a normal juxt if you don't care about performance, but only code clarity.

((juxt (partial filter even?)
                               (partial filter odd?))
                         [1 2 3 4])
And if you do care about performance, and don't want to use transducers, look at juxt-reduce from this so answer: https://stackoverflow.com/a/36321312/172272

enforser20:11:42

do you have an example of input/output?

enforser20:11:24

sounds like something I might use reduce for

enforser20:11:28

(reduce (fn [m v]
          (cond-> m
            (even? v) (update :even conj v)
            (odd? v) (update :odd conj v)))
        {:odd []
         :even []}
        (range 1 10))

;; => {:odd [1 3 5 7 9] :even [2 4 6 8]}

kenj20:11:41

The above was basically what I had in mind (using a map as an accumulator). I just wasn’t sure if that was the most common/idiomatic way to handle that, especially for a larger number of operations/results.

enforser20:11:50

yes, I think so

kenj20:11:31

got it, thanks!

dpsutton20:11:06

That looks like group by

schmee20:11:14

user=> (group-by even? (range 10))
{true [0 2 4 6 8], false [1 3 5 7 9]}

enforser20:11:50

yeah, my example would definitely be better off in group by, but part of what @risinglight was asking for was filtering and applying functions totally independently of each other in one iteration - which group-by would not be ideal for

enforser20:11:26

maybe this is a better example where group-by wouldn't work

(reduce (fn [m v]
          (let [c (fnil conj [])]
            (cond-> m
              (even? v) (update :even c v)
              (odd? v) (update :odd c v)
              :always (update :squares c (* v v)))))
        {}
        (range 1 10))

;; => {:odd [1 3 5 7 9]
;;     :even [2 4 6 8]
;;     :squares [1 4 9 16 25 36 49 64 81]}