Fork me on GitHub
#beginners
<
2020-01-29
>
telekid01:01:04

Curious, is there a bult-in predicate that returns true for list-like things (vectors, lists) but not strings/maps?

andy.fingerhut01:01:19

I can never remember what sequential? returns true vs. false for, but I would check that.

noisesmith01:01:04

it doesn't work for eg. arrays or java.util.List, but it's the right thing for ordered clojure immutable collections

noisesmith01:01:47

nb. also it returns false for sets

andy.fingerhut01:01:58

Its doc string is probably 100% accurate, but tells you very little if you do not know the internal implementation details of data structures.

noisesmith01:01:10

user=> (pprint (group-by sequential? ["hi" 3 [] clojure.lang.PersistentQueue/EMPTY {} #{} () nil]))
{false ["hi" 3 {} #{} nil], true [[] <-()-< ()]}
nil

noisesmith01:01:29

when did we get that nice pr for queues? I like it

andy.fingerhut02:01:01

That is probably some REPL plugin thingy you have. Not part of default Clojure REPL

andy.fingerhut02:01:05

There are also return values of seq that at least some (maybe all except nil?) that sequential returns true for, e.g. (sequential? (seq {:a 1})) is true

andy.fingerhut02:01:26

But I may be getting too far off into the weeds there in my wondering. Part of the reason I am confused by it is that I have actually looked at half a dozen different implementations of seq under the hood in Clojure/Java.

noisesmith02:01:08

hmm, I don't have any plugins - this is just vanilla clj with no deps.edn file

noisesmith02:01:54

the fish version only shows up with pprint, not normal pr

andy.fingerhut02:01:47

Ah, yes, I see it, too. I wasn't using pprint before.

noisesmith02:01:02

anyway, it's a pleasant surprise

seancorfield02:01:52

Looks like it's been in there since Clojure 1.2.

seancorfield02:01:01

1.1 doesn't have clojure.pprint

seancorfield02:01:12

$ clojure -A:1.2 -e "(println *clojure-version*)" -e "(require 'clojure.pprint)" -e "(clojure.pprint/pprint (conj clojure.lang.PersistentQueue/EMPTY :a))"
{:major 1, :minor 2, :incremental 1, :qualifier }
<-(:a)-<

seancorfield02:01:41

(well, that's 1.2.1)

hindol05:01:48

Why is defn / valid but defn // is not? Also, suggest me a name for a division operation which repeatedly divides x with y and returns the count, e.g. (? 125 5) => 3 and (? 250 5) => 3.

seancorfield05:01:41

"'/' has special meaning, it can be used once in the middle of a symbol to separate the namespace from the name, e.g. my-namespace/foo. '/' by itself names the division function."

seancorfield05:01:41

@hindol.adhya You're looking for the opposite of power/exponent?

hindol06:01:16

Yes, exactly. But don't want to name it log.

hindol06:01:55

I went with times-divisible last time, but that's too long. I will be using this frequently.

andy.fingerhut06:01:51

Some variant of the name log seems appropriate for what it does, perhaps with a letter thrown in to mean "floor of log" or "log, truncated"

hindol06:01:53

@U0CMVHBL2 Because the calculation method is different and also because log returns a double. My method returns a whole number.

hindol06:01:56

That's an interesting idea! Thanks. But I really really wanted something like //.

hindol06:01:16

Probably I will go with tlog or similar.

andy.fingerhut06:01:02

/ is not going to work well in Clojure,nor anything that contains /

hindol06:01:20

That part I understood. That's why I am a little sad.

dpsutton06:01:19

(defn -:- [x y] ...)

didibus06:01:50

What about %% ?

hindol06:01:40

%% is valid? "Symbols begin with a non-numeric character and can contain alphanumeric characters and *, +, !, -, _, ', ?, <, > and = (other characters may be allowed eventually)."

hindol06:01:03

It is valid! This is promising.

didibus06:01:56

Ya, I'd say its a little icky as well, since it won't work inside #() cause it'll conflict with that form's %

andy.fingerhut06:01:28

Many things that are not on the list of officially supported characters are not explicitly disallowed -- they just aren't on the officially supported list.

andy.fingerhut06:01:04

/ is one of the few on the explicitly disallowed (or very special restricted use) list.

didibus06:01:48

One hack is if you define a / fn in some namespace, and then alias it to say m you can do (m// 10 5)

hindol06:01:09

Thanks everyone for pitching in. Instead of fighting against the system, I think I'll go with tlog for now.

seancorfield06:01:41

That would probably be my approach to this. Define a new / in a namespace that can get a nice, short alias.

seancorfield06:01:34

user=> (ns times.div (:refer-clojure :exclude [/]))
nil
times.div=> (defn / [a b] (count (take-while #(<= b %) (reductions clojure.core// a (repeat b)))))
#'times.div//
times.div=> (ns user)
nil
user=> (require '[times.div :as *])
nil
user=> (*// 250 5)
3
user=> (*// 125 5)
3
user=>
(updated to add :refer-clojure :exclude so the warning about redefinition doesn't appear)

hindol19:02:43

Reviving and old thread, but I did a cool (to me) implementation of int-log.

(defn int-log
  "Returns how many times b can evenly divide x."
  [x b]
  (let [squares (reverse
                 (map vector
                      (iterate #(* 2 %) 1)
                      (take-while #(zero? (rem x %))
                                  (iterate #(*' % %) b))))]
    (loop [[[i m] [j n] & squares] squares]
      (if (nil? n)
        i
        (if (zero? (rem x (* m n)))
          (recur (cons [(+ i j) (* m n)] squares))
          (recur (cons [i m] squares)))))))
This one calculates the exponent in logarithmic time O(log n). Benchmarked against a naive O(n) implementation.
(defn int-log-naive
  [x b]
  (count
   (->> (iterate #(*' b %) b)
        (take-while #(zero? (rem x %))))))
(defn -main
  [& _]
  (let [base   29
        raised (math/expt base 1000)]
    (dotimes [_ 1000]
      (? raised base))))

(time
 (-main))
int-log: "Elapsed time: 113.5178 msecs" int-log-naive: "Elapsed time: 11103.9029 msecs"

hindol19:02:47

For (int-log 1250 5), 1. collect enough squares [5 25 625] 2. start with the highest square 625 3. (* 625 25) divides 1250? if not, drop 25. (* 625 5) divides 1250? if not drop 5.

LorenzoEvans16:01:02

Would anyone be able to point me to some information on why a ClojureScript application (re-frame template +handler) wouldn’t show updates on a custom domain when changes are pushed to master with GitHub integration, but will show them on the herokuapp? I’ve ran git add ., git push heroku master(:master), lein prod, lein with-profile prod uberjar, pulled my changes into master and committed that, I’ve ran git push --force, and still, the changes will not take to the new site? I’ve scoured through some S/O answers but most of them are for languages/platforms that aren’t Clojure/S.

Eamonn Sullivan16:01:00

Just a dumb question, but have you eliminated caching? Each browser has a different way of busting the cache -- in Chrome, shift-click on reload, for example.

LorenzoEvans16:01:28

Oh my dear god that was it. That was it! Thanks so much, I’ll never forget it.

alpox20:01:37

@UHR1B0NJG For future reference: There is a small trick to always force the browser to use the most recent version of your script and ignore cache. When loading your script you can add a version-identifier as any query parameter. For example: app.js?v=1.0 as soon as the browser sees another query string it won't load from cache

alpox20:01:54

We sometimes use this to ensure that clients get the newest version and we don't get calls which are resolved by a simple cache reload

Luke Schubert12:01:44

I know the angular bundler solves this by adding some random string to the end of its generated js files

Luke Schubert12:01:19

so for v1.0.0 all of the built js will be bundle-45ASDB123.js and the index.html file will reference that, and when you bump to v1.0.1 that random string will change

Victor FM23:01:09

Hey everyone, I'm having trouble managing response types on a API, like sending a 200, 422, or any other status, does anyone have this problem too? I'm using compojure to design it

noisesmith23:01:26

how are you setting the response status?

Victor FM23:01:50

At the moment it is always sending back a 200, with the contents on the body

noisesmith23:01:08

there's a helper, but a hash-map {:body ... :status N} should do the trick

Victor FM23:01:27

I'm trying to figure out how to set up the responses types without applying that on the business layer

Victor FM23:01:53

I have 3 layers, the API, business, and repository

Victor FM23:01:16

If I add the logic to send back a 422 for example, where would I put it? On the API layer or the business layer? If I add it in the business layer, it wouldn't really be a business layer anymore, right?

noisesmith23:01:38

likely a middleware that takes your handler as an argument and returns a new handler that validates that the request can be processed, and falls back to 422

noisesmith23:01:38

but I haven't isolated my layers in as disciplined way as you are describing, so I might be missing a better option

noisesmith23:01:23

I'm also slightly confused by your usage of the term "response type" here because to me that's somehting like application/json

noisesmith23:01:33

which clearly isn't what you mean

Victor FM23:01:24

sorry, I mean sending back a 422 when someone sends a invalid entity, like a missing field or wrong information type

noisesmith23:01:40

OK yeah I'd definitely write a wrap-validate middleware and wrap the handler with it (inside the route if it's endpoint specific, around the router if it's generic)

Victor FM23:01:57

hmm, ok I'll take a look on how to create middlewares then, maybe that's what I'm missing

noisesmith23:01:15

the platonic form of a handler middleware:

(defn wrap-foo
  [handler-function]
  (fn new-handler-function [request]
    (post-function (handler-function (pre-function request)))))
it takes a handler, and returns a new one that might do something with data before the handler is called, and might do something after the handler is called

noisesmith23:01:53

a validator is probably more like this:

(defn wrap-validate
  [handler-function]
  (fn [request]
     (let [validation-error (validate request)]
        (if validation-error
           {:status 422 :body validation-error}
           (handler-function request)))))

noisesmith23:01:41

where validiate returns nil or false for a good input, and a message for a bad one

Victor FM23:01:31

ok, that makes it way easier to understand

Victor FM23:01:55

you helped me a lot, thanks! I was thinking the whole day about this

noisesmith23:01:53

so instead of using layers per-se (or as well as), you can isolate concerns into middleware, and compose them on each other to get all your needed features (there are a lot of great middleware that come with ring, many are applied already by default)

Victor FM23:01:35

that is a interesting approach, I'll have to think more on that and decide what to do

noisesmith23:01:43

and another variation is that wrap-validate can take another arg- the validator rules (or validator function) and individually get wrapped on different contexts

noisesmith23:01:40

since in ring the router itself is wrappable (for things that apply to all routes) but so are individual endpoints (for things that are route or subtree specific)

Victor FM00:01:53

you mean adding the middleware only for a specific route?

noisesmith00:01:37

right - they are flexible enough to be applied at either level

noisesmith00:01:01

(or maybe better to say, ring's design is such that they can be applied at either level)

Victor FM00:01:03

Ok, thanks for all the help man, I'll try work on it