Fork me on GitHub
#beginners
<
2020-12-08
>
Hagenek00:12:24

Hi everyone! When solving Advent of Code day 3, At around 20 minutes in, Lambdaisland uses a symbol called input->map, this does not work for me. https://www.youtube.com/watch?v=wXVDfzxeZ-o&amp;ab_channel=LambdaIsland . Is it his own macro? Here is my code that gives the error:

(defn sled-down [input]
  @(first
    (drop-while 
     (complement reduced?)
     (iterate sled [(input->map input) 0 0 0]))))

Hagenek00:12:40

Ahh thank you, missed that he changed that. Time for bed!✌️Not used to using -> in function names

noisesmith00:12:01

it's surprising that it doesn't return a hash-map

noisesmith00:12:07

oh, it's a different kind of "map" (as if the two we have aren't enough)

Ronny Li01:12:09

Hi, I've seen some reitit handlers extract the following keys from `request`:

{:keys [path-params query-params body-params]}
Yet when I inspect my request map I only see
:query-string
:path-params
:body
Does anyone know the reason for this discrepancy? Am I on the wrong version of reitit? I'm using `[metosin/reitit "0.5.10"]`

hiredman01:12:49

It will depend on the middleware you modifying the request before it gets to your handler

Ronny Li03:12:58

Thank you so much! That makes a lot more sense.

hiredman01:12:21

I think body-params comes from some kind json parsing middleware

hiredman01:12:11

You can also have form-params which comes from the middleware that parses the body as an encoded form post

Felix M02:12:29

Hi, what's the difference between Reagent and Re-frame? When would you either or both to build SPAs? thanks

Ronny Li20:12:02

I'll slightly re-word what Sean said, Reagent is basically React and Reframe is basically Redux.

Ronny Li20:12:41

This means that for simple stuff you only need Reagent but if at any point you start having headaches when managing app state then you should consider Reframe

🙏 3
seancorfield03:12:01

@heyhey I'm no expert -- I don't do any cljs -- so I'm basing this on just reading the respective websites for those two projects: re-frame is a reactive framework built on top of Reagent -- Reagent is a low-level wrapper around React. We looked at doing some cljs work back in 2013/2014 and the choice then was Om or Reagent and we built an SPA with both. We liked Reagent a lot more. My understanding is that re-frame is a higher-level approach that makes building more complex SPAs easier than with just Reagent (in the same way that Redux brings structure to React apps to help manage dataflow better). There are #reagent and #re-frame channels here if you want to ask more in-depth questions.

👍 3
scythx05:12:23

Has anybody ever tried to deploy clojure-webapp on cpanel?

evocatus09:12:02

If I need to, let's say, calculate sum of even numbers between 1 and 1000 I would do it like this:

(->> (range 1 1000)
     (filter even?)
     (reduce +)
)

evocatus09:12:21

But what if I need to do the same for numbers that are either divisible by 3 or divisible by 5?

evocatus09:12:21

Is there a better way than checking for this complex condition at once?

evocatus09:12:55

Like

(or #(zero? (rem % 3))
    #(zero? (rem % 5)))

Ben Sless09:12:03

First you can abstract it a little by using some-fn:

(doc some-fn )
-------------------------
clojure.core/some-fn
([p] [p1 p2] [p1 p2 p3] [p1 p2 p3 & ps])
  Takes a set of predicates and returns a function f that returns the first logical true value
  returned by one of its composing predicates against any of its arguments, else it returns
  logical false. Note that f is short-circuiting in that it will stop execution on the first
  argument that triggers a logical true result against the original predicates.

😮 3
Ben Sless09:12:37

Then you can define a little helper:

(defn divisible? [n] (fn [k] (zero? (rem k n))))

Ben Sless09:12:56

Already you can create something like:

(some-fn (divisible? 3) (divisible? 5))

Ben Sless09:12:26

if you want to go one level further you can take any number of divisors:

(defn divisible-by-either? [xs] (apply some-fn (map divisible? xs)))

Ben Sless09:12:27

Then you'd write

(->> xs (filter (divisible-by-either? [3 5])) (reduce +))

evocatus09:12:56

Thanks! some-fn is killer

Ben Sless09:12:37

You're welcome. Be sure to say hi to her evil twin, every-pred

(doc every-pred )
-------------------------
clojure.core/every-pred
([p] [p1 p2] [p1 p2 p3] [p1 p2 p3 & ps])
  Takes a set of predicates and returns a function f that returns true if all of its
  composing predicates return a logical true value against all of its arguments, else it returns
  false. Note that f is short-circuiting in that it will stop execution on the first
  argument that triggers a logical false result against the original predicates.

Daniel Stephens11:12:40

Hi all, Is there a way to get clojure.java.jdbc to return LocalDates/Instants rather than the java.sql.Timestamp/Date values? I have an issue where I store a BCE date correctly but it pulls it back flipped to a positive value. 0000-01-01 local dates gets stored as 0001-01-01 BC postgres date correctly, gets read as 0001-01-01 java.sql.Date wrongly.

(query "SELECT CAST(date_col AS VARCHAR) FROM table")
=> [{:date_col 0001-01-01 BC}]


(query "SELECT date_col FROM table")
=> [{:date_col #inst "0001-01-01T00:00:00.000-00:00"}]

^ techincally this is a java.sql.Date but as it extends java.util.Date clojure formats it as an instant, either way it's lost the ERA.

Daniel Stephens11:12:58

I'm on 'latest stable' 0.7.11 but not sure if it's this library or an underlying one that gets it wrong

souenzzo11:12:30

Maybe ask in #sql channel

👍 3
Chris13:12:03

Hi all, how can I run a single clojure file with a dependency? I have the following file:

(require '[hickory :as h])

(defn run
  []
  (->> (slurp "some.html")
       h/parse
       h/as-hickory
       :content
       first
       :content
       (filter #(= (:tag %) :body))))

(println (run))
And I’m trying to run it using:
clj -Sdeps "{:deps {hickory {:mvn/version \"0.7.1\"}}}" script.clj
However, I get:
Could not locate hickory__init.class, hickory.clj or hickory.cljc on classpath

Chris13:12:41

I tried changing the first line to:

(ns script
  (:require [hickory :as h]))

Chris13:12:46

But it did not change anything

Chris13:12:25

Sorry, I found my mistake facepalm I had to do (require '[hickory.core :as h])

andy.fingerhut14:12:37

According to the README for the hickory project, the namespace to require is called hickory.core, not hickory. Try changing that in your require form.

Chris14:12:19

Yes, that was my mistake, everything works fine now! Thanks!

Felix M14:12:18

@seancorfield thank you, that's exactly the overview I needed. So, Re-frame is a framework built on top of Reagent, along the lines of Next.js for React. Got it.

Miles R.19:12:40

Hi! I'm an electrical engineer looking to pick this up for some SPA hobby projects. Primary development experience is in windows desktop applications in C++ and C#, as well as far less relevant 8 bit embedded applications

👋 6
Miles R.19:12:45

I have a skeletonized project established in IntelliJ (2018.3.6 Ultimate Edition) using Cursive and Leiningen, I want to eventually deploy it using something like heroku but coming from byte level shenanigans at my current job there's a lot to take in all at once

Miles R.19:12:05

to keep things simple starting out I've created a new project using the command lein new luminus {project name} +re-frame that builds and runs fine when I set it to run the -main segment from my .core project file, after that I point firefox at the correct page and it returns this message saying I haven't compiled my clojurescript yet:

Pavel Klavík21:12:17

You need to run two things. Server is runned by lein run while you also need to run client hot code reloading compliation, which is in your case likely lein figwheel (I am using Shadow-cljs for that.)

Pavel Klavík21:12:23

It works that server is serving HTML and JS file from resources directory, and JS is created there by running lein figwheel. When you build production version, it will build production version of JS and package everything inside uberjar so the server can serve it.

Miles R.19:12:10

popping over to the terminal in my IDE I try running the suggested command and it returns that 'lein' is not recognized

phronmophobic20:12:31

does it work if you type the command wherever you typed in: lein new luminus {project name} +re-frame?

Miles R.20:12:08

I put that command back together from the new project wizard where it decompiles it into separate project name, template, and template settings fields, my IntelliJ definitely is running lein under the hood I'm just not sure how to access that directly

Jeff Evans20:12:10

what’s the idiomatic way to efficiently (i.e. binary search) a sorted vector for a value?

(let [sorted-vec (vec (sort [10 2 0 99 -18 72 10]))
  ...?)
(contains? sorted-vec n) works, but it’s not efficient

phronmophobic20:12:22

depending on the use case, the idiomatic solution might be to use a different data structure. this stack overflow solution also looks reasonable, https://stackoverflow.com/questions/8949837/binary-search-in-clojure-implementation-performance#8950240

Jeff Evans20:12:10

yeah, I tried the Java interop way, but got some cast exceptions between Integer and Long, and kind of gave up on it. decided to see if there was a more built-in, idiomatic way

phronmophobic20:12:42

would sorted-set work for your use case?

phronmophobic20:12:47

there are also a dozen data structures listed at https://www.clojure-toolbox.com/ that perform well for different use cases

Jeff Evans20:12:21

thank you, will have a look. and yeah, in this particular case, sorted-set would work, so that’s a good point

noisesmith21:12:46

regarding contains? above, that should be instant, and only look for the index by position, not the value held

noisesmith21:12:12

also, with a sorted-set you can use subseq / rsubseq to iterate in a way that takes advantage of the binary tree implementation (eg. using the branching to quickly find the first item > your start-key)

noisesmith21:12:15

demo of the contains? issue:

user=> (let [sorted-vec (vec (sort [:c :a :b :d]))] (contains? sorted-vec 0))
true

noisesmith21:12:26

that is true because there is an item at index 0

Miles R.20:12:25

anyways I managed to successfully deploy: http://kobold.xyz/

Miles R.20:12:44

(It's empty but hey that it works at all is pretty promising)

metal 3
Miles R.21:12:35

Basic question, how do I serve up the favicon.ico as part of the slug? the normal HTML method results in a 404 when attempting to access it

noisesmith21:12:03

@milesred42 typically I have made a middleware that short-circuited all requests for "/favicon.ico" regardless of parent with a resource response containing the correct image file

noisesmith21:12:27

there might be something premade for this...

noisesmith21:12:38

this stack overflow answer is about the same as what I did https://stackoverflow.com/a/51978184

Miles R.21:12:56

kk, i'll look into that

noisesmith21:12:54

of course this means you need to have a "favicon.ico" file, most likely in your resources/ folder so that it will be present in your packed jar

Miles R.21:12:47

yeah it's already in resources/public/ so it should be pretty easy to redirect those requests

noisesmith21:12:04

it's not a redirect, it's an override of your routing handler

noisesmith21:12:23

I mean, you could also define favicon.ico as a route, that's just less idiomatic

noisesmith21:12:45

@milesred42 also, depending on how you deploy (and what kind of site / level of usage you are expecting) you might have a reverse proxy or CDN setup anyway, and in that case it's easier to just define the favicon statically and ignore it in clojure world

Jeff Evans22:12:51

is there a way to constrain the size of the thread pool used for future and deref ? or does one need to use this approach (`set-agent-send-off-executor!`)? https://stackoverflow.com/questions/11316737/managing-agent-thread-pools-in-clojure#comment108769284_11322660

phronmophobic22:12:36

you could also create your own future that uses whatever executor your want. the clojure.core code wouldn't be that hard to modify:

(defn future-call 
  "Takes a function of no args and yields a future object that will
  invoke the function in another thread, and will cache the result and
  return it on all subsequent calls to deref/@. If the computation has
  not yet finished, calls to deref/@ will block, unless the variant
  of deref with timeout is used. See also - realized?."
  {:added "1.1"
   :static true}
  [f]
  (let [f (binding-conveyor-fn f)
        fut (.submit clojure.lang.Agent/soloExecutor ^Callable f)]
    (reify 
     clojure.lang.IDeref 
     (deref [_] (deref-future fut))
     clojure.lang.IBlockingDeref
     (deref
      [_ timeout-ms timeout-val]
      (deref-future fut timeout-ms timeout-val))
     clojure.lang.IPending
     (isRealized [_] (.isDone fut))
     java.util.concurrent.Future
      (get [_] (.get fut))
      (get [_ timeout unit] (.get fut timeout unit))
      (isCancelled [_] (.isCancelled fut))
      (isDone [_] (.isDone fut))
      (cancel [_ interrupt?] (.cancel fut interrupt?)))))
  
(defmacro future
  "Takes a body of expressions and yields a future object that will
  invoke the body in another thread, and will cache the result and
  return it on all subsequent calls to deref/@. If the computation has
  not yet finished, calls to deref/@ will block, unless the variant of
  deref with timeout is used. See also - realized?."
  {:added "1.1"}
  [& body] `(future-call (^{:once true} fn* [] [email protected])))

phronmophobic22:12:40

you could even modify it to allow for an executor to be passed in if you wanted something like multiple thread pools

phronmophobic22:12:42

or you could interop with an implementation of executor directly, https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Executor.html

Jeff Evans03:12:05

I’m a bit surprised there isn’t a different-arity version of future-call that accepts the executor to use as a param (with the current arity one simply passing clojure.lang.Agent/soloExecutor as it uses now). Seems like it would avoid having to reimplement things

Ben Sless04:12:57

What you want doesn't exist in core clojure but others have got you covered https://github.com/TheClimateCorporation/claypoole

phronmophobic05:12:38

regarding not having a param for passing an executor, I think it's because it's an implementation detail. I think future is only meant to fulfill a basic need. anything more complex than that and it would probably be better suited as a stand-alone library rather than a core feature.

hiredman22:12:03

deref doesn't use a threadpool

Jeff Evans22:12:27

ah, right, it’s just waiting for the future to finish

Jeff Evans22:12:39

I guess amend that to “control the number of threads used to execute futures”

hiredman22:12:53

I've never used set-agent-send-off-executor! or any of the via functions

hiredman22:12:42

I use executors a fair bit, and deref works on java Futures just fine

Jeff Evans22:12:56

do you have a sample code snippet, by chance?

Jeff Evans22:12:05

trying to understand what I need to change to use those instead

Jeff Evans22:12:35

reading Clojure Applied, and it talks about using Java thread pools but doesn’t show an example of how to use them along with Clojure futures

hiredman22:12:39

https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Executors.html has a bunch of static methods for creating different kinds of executors

hiredman22:12:32

when you schedule work do be done on an executorservice you often get back a https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Future.html which deref supports

noisesmith22:12:39

a clojure future is just a wrapping of dynamic var binding plus .submit of an fn to an executor - check out the source of future-call which the future macro uses, it's pretty small

Jeff Evans22:12:14

thanks, all. I have some reading to do

dpsutton22:12:44

future submits to Executors.newCachedThreadPool so i don't believe there's any way to constrain the number of spawned threads using that macro