Fork me on GitHub
#beginners
<
2017-06-27
>
stardiviner01:06:05

@curlyfry Thanks your solution.

clj.max05:06:01

question about "splitting the thread" using ->>

clj.max05:06:13

I want to calculate the avg of a list of numbers

clj.max05:06:37

so I need to both (reduce +) and count in my thread

clj.max05:06:46

but I can't figure out how to "split" and "merge" it?

clj.max05:06:56

currently I'm just using "imperative let" programming šŸ˜‰

clj.max05:06:34

i.e. (let [sum (reduce + numbers) length (count numbers)] (/ sum length))

clj.max05:06:03

feels almost perfect for ->>, if only I could figure out a way to get both the sum and the count threaded in there..

stardiviner06:06:04

How to get current working directory in Clojure?

noisesmith06:06:04

on UNIX platforms (System/getenv "PWD") gives the right answer

noisesmith06:06:58

actually I bet

(.getCanonicalPath ( "."))
is the most reliable option

stardiviner06:06:40

@noisesmith What is .getCanonicalPath?

noisesmith06:06:18

it's a method on a java.io.File object, which http://clojure.java.io/file creates

a1309:06:31

(System/getProperty "user.dir")
should work too

manutter5111:06:52

@clj.max ->> is for threading, not splitting. Itā€™s for when you want to take an argument, then apply function x to it, then apply function y to the result, then function z to the result of that, etc.

manutter5111:06:31

I think your ā€œimperative letā€ approach is the most straightforward way to do it in this case. You could also do (defn avg [coll] (/ (reduce + coll) (count coll))), but the ā€œletā€ approach is slightly more explicit as to what you are doing. IMO code is easier to maintain when itā€™s more explicit

a1313:06:12

jff one-pass average with threading šŸ™‚

(defn avg
       [coll]
       (let [{:keys [sum cnt]}
             (reduce 
              (fn [acc x]
                (-> acc
                    (update :sum (partial + x))
                    (update :cnt inc)))
              {:sum 0 :cnt 0}
              coll)]
         (when-not (zero? cnt)
           (/ sum cnt))))

noisesmith13:06:27

that's a really good piece of evidence that threading makes no sense for this

noisesmith13:06:47

(when compared with the simpler alternatives)

noisesmith13:06:06

other silly ways to get an average include

(apply / ((juxt (partial apply +) count) coll))

a1313:06:46

another, recursive one šŸ™‚

(defn avg
       [coll]
        (loop [[x & xs] coll avg 0 n 0]
          (let [nextn (inc n)
                avgn (/ (+ x (* n avg)) nextn)]
            (if (seq xs)
              (recur xs avgn nextn)
              avgn))))

harrigan13:06:02

Is this a good channel to ask a (beginner) spec question?

curlyfry14:06:52

@harrigan Sure, here or #clojure-spec

harrigan14:06:16

(s/def ::fixed-length (s/& (s/+ int?) #(= 2 (count %))))

(defn variable-length?
  [{:keys [length data]}]
  (= length (count data)))

(s/def ::variable-length (s/and (s/cat :length int?
                                       :data (s/* int?))
                                variable-length?))

(s/conform ::fixed-length [1 2]) ;; => [1 2]

(s/conform ::variable-length [2 1 1]) ;; => {:length 2, :data [1 1]}

(s/conform (s/cat :fixed ::fixed-length
                  :variable ::variable-length)
           [1 2 2 1 1]) ;; => :clojure.spec.alpha/invalid

harrigan14:06:45

I have three specs: ::fixed-length, ::variable-length and the two combined. The first two work as expected individually.

harrigan14:06:18

But I canā€™t combine them.

harrigan14:06:24

It looks like ::fixed-length is too ā€œgreedyā€ but Iā€™m not sure how to prevent this.

a1314:06:35

What output are you trying to get from the last s/conform?

a1314:06:41

smth like

{:fixed [1 2] :variable {:length 2, data [1 1]}}
?

clj.max14:06:09

@manutter51 thanks, good to know. i'll leave it as a let then.

a1315:06:01

@harrigan

(s/def ::fixed-length (s/& (s/+ int?) #(= 2 (count %))))

(defn variable-length?
  [{:keys [length data]}]
  (= length (count data)))



(s/def ::variable-length
  (s/& (s/cat :length int? :data (s/* int?))
       variable-length?))

(s/conform (s/cat :fix ::fixed-length
                  :var ::variable-length)
           [1 2 3 1 1 1])

harrigan15:06:32

Thanks @a13 , thatā€™s exactly what I was looking for. I need to read up on the distinction between s/& and s/and.

madstap15:06:56

@harrigan The difference is that regex specs concatenate, while non-regex specs nest. For your first attempt [1 2 [2 1 1]] is valid.

madstap23:06:52

@drewverlee In specs: (fdef identity :args (s/cat :x any?))