Fork me on GitHub
#beginners
<
2021-10-06
>
dbernal01:10:40

So I started my REPL executed this line of code:

(slurp (io/resource file))
Then changed that file to have different contents, executed the same function, but the result from slurp hasn’t changed. Just wondering why or if I’m doing something wrong

alexmiller01:10:05

resources are read from the classpath. it seems likely that you're reading that file out of a jar or something, not off the file system

alexmiller01:10:14

like, don't slurp it - you should get a url to the location

alexmiller01:10:24

(io/resource file)

dbernal01:10:17

Once I get the URL how do I get the contents out?

alexmiller01:10:35

there are other ways (basically what slurp is doing under the hood - getting a URL connection, reading the stream, etc)

dbernal01:10:50

Sorry, figured out what I did wrong. I modified the file at the root of the project but I had my resources points at /resources

alexmiller01:10:28

keep in mind that resources are loaded by the classloader and I think cached in the loader so you still may not see updates

dbernal01:10:02

Oh so stuff specified in :resource-paths may not load still?

alexmiller01:10:18

it will, it just may not see updates after you load the resource

alexmiller01:10:32

or maybe that's what you were asking

dbernal01:10:10

gotcha, I understand, if I modify the file I would have to call (io/resource …) again

dbernal01:10:16

is that right?

alexmiller01:10:16

well yes, I was suggesting that might not be enough, but I was wrong - it looks like it will see updates in file system files

alexmiller01:10:25

and actually, no you don't have to call resource again, just re-`slurp`

dbernal01:10:46

Got it. ty so much for the info!

Benjamin07:10:03

let's say I want to share config / resoiurces between 2 projects, how would you do it? Is there a simpler way than just having the same file in 2 places?

delaguardo07:10:55

it depends on how those two projects works together. Are they completely independent running projects or one uses another as a dependency?

Benjamin07:10:19

they dont' depend on each other. It's like a serive and aws lambda that share credentials etc

didibus09:10:28

I'm not too sure what you're trying to achieve, but you can have two programs use the same file that is either on the file system or some remote store. For example, just have them slurp the same file

didibus09:10:40

You might need to explain what you mean by project as well in this case.

Redbeardy McGee08:10:38

I've been deliberating this issue for a while. The library is deprecated, but it's the only one available for clojure and only seems to need a few little patches to work with the current state of the API. My question is if there may be an approach to resolve the issue with a non-breaking change, or if a breaking change would just be the more appropriate thing to do instead. https://github.com/cjsauer/pubg-clj/issues/2

quan xing14:10:49

I create a demo use hugsql with vscode. when I run calva and press key Ctrl+Enter and show error. but this demo in clj is ok

alpox14:10:54

You may not have evaluated the namespace form after adding new requires. With Ctrl-Alt-C Enter you can evaluate the whole file again after which the namespace should required.

2
quan xing15:10:12

I press the Ctrl-Alt-C Enter and Ctrl+Enter eval form but it's show error yet.

; Evaluating file: core.clj
; Syntax error (FileNotFoundException) compiling at (d:\E\clojure\hugsql\ted\src\ted\core.clj:1:1).
; Could not locate ted/db__init.class, ted/db.clj or ted/db.cljc on classpath.
; Evaluation of file core.clj failed: class clojure.lang.Compiler$CompilerException
every .clj file with press Ctrl-Alt-C Enter ?

Colin P. Hill15:10:12

I’m trying to write a macro which accepts a sequence of expressions and ultimately yields a map. Right now I’m accomplishing this with (into {} …). One way I’d like to improve it is to get the same validations as when using a map literal, e.g.,

user=> {:foo :bar :foo :baz}
Syntax error reading source at (REPL:8:22).
Duplicate key: :foo
Is there any way to accomplish this without re-implementing that check by hand?

dgb2316:10:57

accomplish this as in throw an error?

dgb2316:10:58

note that this error is thrown when the map literal is read. https://clojure.org/reference/reader

Colin P. Hill16:10:06

Yes, as in throw an error

dgb2318:10:49

For me it would be easier to help looking at the current implementation.

Colin P. Hill21:10:48

The full details are app-specific. The relevant bit is that I wind up with a sequence of pairs (e.g., ([:foo :bar] [:baz :bork])) and need to turn this into a map. Currently doing that by handing it to into, but this means just overwriting duplicate keys instead of erroring on them.

George Silva18:10:55

Hello friends. I have a puzzling situation here I haven't been able to figure it out. I have the following piece of code:

(defn haversine
  "Distance in km between two points of lat/long. Supply two maps of latitutde and longitude."
  [{lat1 :lat long1 :lng}
   {lat2 :lat long2 :lng}]
  (if (every? float? '(lat1 lat2 long1 long2))
    (let [delta-lat (Math/toRadians (- lat2 lat1))
          delta-long (Math/toRadians (- long2 long1))
          lat1 (Math/toRadians lat1)
          lat2 (Math/toRadians lat2)]
      (* earth-radius 2
         (Math/asin (Math/sqrt (alpha lat1 lat2 delta-lat delta-long)))))
    0))
Basically it uses destructuring to fetch out lat and lng from maps and proceeds to calculate the distance between two points. I've added the (if (every? float? check, because my maps sometimes, can be nil. Instead of evaluating to zero, I'm getting the following error: Execution error (NullPointerException) at clrips.haversine/eval9073 (form-init7532735855317168820.clj:2126). Is there any catch I'm not aware of? Or is the code just wrong?

alexmiller18:10:01

what's (pst *e) show? What's alpha?

phronmophobic18:10:08

it's almost certainly (every? float? '(lat1 lat2 long1 long2)). should be (every? float? [lat1 lat2 long1 long2])

George Silva19:10:47

I've tried both ways 🙂 both with the same result

phronmophobic19:10:35

float? will return false for integers, so if you pass 42 rather than 42.0, float? will be false. You can also try using number? rather than float?. It depends on the types of calculations if you want to coerce yourself or force the caller to coerce.

👍 1
dgb2318:10:44

I don’t think that’s the problem, both are sequences right?

phronmophobic18:10:27

right, but the first is a sequence of symbols and the second is a sequence of the values bound to lat1 , lat2 , etc

dgb2318:10:36

earth-radius and alpha are the big unknowns in this code

dgb2318:10:32

right 😄

dgb2318:10:46

so easy to overlook

phronmophobic18:10:10

> (let [[lat1 lat2 long1 long2] [1 2 3 4]]
     (prn ''(lat1 lat2 long1 long2) '(lat1 lat2 long1 long2))
     (prn '[lat1 lat2 long1 long2] [lat1 lat2 long1 long2]))

;; (quote (lat1 lat2 long1 long2)) (lat1 lat2 long1 long2)
;; [lat1 lat2 long1 long2] [1 2 3 4]
not sure that helps, but there's a difference between '(a b c) and (list a b c)

phronmophobic18:10:16

> I've added the `(if (every? float?` check, because my maps sometimes, can be `nil`. I would also caution against combining error recovery and calculation into this one function. It might be convenient in this specific use case, but if haversine is ever used in another context, it's likely that passing nil will be an error and returning 0 will only cover up the error and produce incorrect results that are hard to debug.

👍 1
dgb2318:10:45

a precondition/throwing would be the right thing to do here right?

dgb2319:10:10

maybe dispatching “outside” with a multimethod, protocol/record or something like that seems sensible too.

phronmophobic19:10:25

If it happens to be a very common idiom, it might also be acceptable to combine the two in an appropriately named function like some-haversine . Seems unlikely in this case, but generally speaking, it might be ok. I might still prefer to keep them separate and have some sort of threading macro.

George Silva19:10:12

The mixing between the functionality / error identification / throwing all make sense, thanks for the tips. Let me try a different approach 🙂

George Silva19:10:23

I got to this:

(defn haversine
  "Distance in km between two points of lat/long. Supply two maps of latitutde and longitude."
  [{lat1 :lat long1 :lng}
   {lat2 :lat long2 :lng}]
  {:pre [(every? float? [lat1 long1 lat2 long2])]}
  (let [delta-lat (Math/toRadians (- lat2 lat1))
        delta-long (Math/toRadians (- long2 long1))
        lat1 (Math/toRadians lat1)
        lat2 (Math/toRadians lat2)]
    (* earth-radius 2
       (Math/asin (Math/sqrt (alpha lat1 lat2 delta-lat delta-long))))))

(defn safe-haversine [a b]
  (try
    (haversine a b)
    (catch AssertionError ex 0)))
This is much cleaner to read actually. looks to be working.
(safe-haversine {:lat 1.0 :lng 0.0} {:lat 0.1 :lng nil})
0
clj꞉clrips.haversine꞉> 
(safe-haversine {:lat 1.0 :lng 0.0} nil)
0
clj꞉clrips.haversine꞉> 
Thanks!

🎉 1
George Silva21:10:37

So - do you want to feel stupid, like I did? So I'm testing it out here and created the above code using symbols. you know :lat :lng. But nothing was working. My manual tests in calva were working! Distance was returning, when being called manually. But when I tried to run by reading data from JSON using cheshire, nothing. always zero. So, here is an example on how things are coming from JSON. :face_palm: {"lat" 51.54987, "timestamp" "2018-08-10T20:04:22Z", "lng" 12.41039} BTW - Calva breakpoints are great. Just learned how to use them. Again, thanks for all the help!

Lukas21:10:43

😅 ouh I know that feel. This has also happened to me

George Silva21:10:01

BTW, how can I make cheshire to decode the json with symbols instead of strings?

George Silva21:10:22

keywordize-keys will do the trick

solf21:10:15

Directly from cheshire passing a second argument true like:

(cheshire/parse-string "..." true)

George Silva21:10:06

@U7S5E44DB cool, but the docs are very lean. I'm using parse-stream. I could not find how to pass options... Are they the same options for parse-string?

solf21:10:52

Should be

solf21:10:00

The second argument can be true, in which case it defaults to keywordizing the keys, or any function

solf21:10:22

So it’s the same as

(ch/parse-stream ... keyword)

🤯 1
George Silva23:10:17

I think I was looking at a different version of the docs :face_palm:

Lukas21:10:58

Hey guys, is there a way to implement how a type should be represented in the repl? I have this cons-cells

(defprotocol cons-cell
  (car [this])
  (cdr [this]))

(deftype Cons [l r]
  cons-cell
  (car [this] (.l this))
  (cdr [this] (.r this)))
and I would like them to look like an ordinary clojure list, when evaluating them. Is this possible?

alexmiller21:10:46

Printing is controlled by print-method and print-dep multimethods (the caveat being that they will be read back as lists, not your type)

alexmiller21:10:08

You can implement those methods to get this

Lukas21:10:46

Awesome, thanks a lot 🙏

vlad_poh23:10:14

what is the easiest way to slurp a binary