Fork me on GitHub
#beginners
<
2021-01-17
>
Harley Waagmeester03:01:43

interleave sounds very useful, but i seldom see it used

Harley Waagmeester03:01:56

(def goof '(:a 1 😛 2 :c 3))

Harley Waagmeester03:01:29

i might expect an error from (:a goof)

Harley Waagmeester03:01:00

(get :a goof) => nil

Harley Waagmeester03:01:27

(get goof :a) => nil

Harley Waagmeester03:01:44

that's at the cider repl

Harley Waagmeester04:01:02

... or nil if key not present ... technically correct

andy.fingerhut04:01:43

get on a list (with parentheses) always returns nil, I believe. It is more useful when given a first arg that is a vector or a map, not a list.

Harley Waagmeester04:01:20

@seancorfield i haven't compiled code with that syntax, and i wonder if it should compile without an error, i stretch the limits of all software i use, and get nervous when i discover nonsensical code that compiles, i mean we can't have walmart giving away free teslas or anything

seancorfield04:01:59

Do you think it is "nonsensical code"?

didibus04:01:57

get won't throw, it returns the key when present or nil

didibus04:01:25

> Returns the value mapped to key, not-found or nil if key not present.

didibus04:01:48

This is true also if what you pass to get is not associative, it considers that like the key isn't on the thing since the thing cannot even associate keys to values

didibus04:01:22

If you want it to throw, you should use the map as a function: (goof :a)

didibus04:01:43

This will help catch if you're not actually using an associative

Harley Waagmeester04:01:17

it just bothers me that the code doesn't make sense, it accomplishes nothing because it is garbage code, i think it is, and it still gets evaluated without an error

seancorfield04:01:12

It makes perfect sense once you understand Clojure's semantics.

Harley Waagmeester04:01:19

(goof :a) is new to me

seancorfield04:01:51

Because nil-punning is core to Clojure's idioms. So returning nil here is far more useful (and idiomatic) than throwing an exception.

seancorfield04:01:51

Associative data structures also implement function semantics: they look up their argument in themselves. Keywords also implement function semantics: they look themselves up in their argument.

seancorfield04:01:22

user=> (get [1 2 3 4] 2)
3
user=> (nth [1 2 3 4] 2)
3
user=> (get [1 2 3 4] 100)
nil
user=> (nth [1 2 3 4] 100)
Execution error (IndexOutOfBoundsException) at user/eval6035 (REPL:1).
null

seancorfield04:01:58

We have both approaches for different contexts.

Harley Waagmeester04:01:00

yes that is the gist of it, i think the keyword function should only work with maps, that's all i am concerned weith

seancorfield04:01:29

user=> ([1 2 3 4] 2)
3

Harley Waagmeester04:01:34

oh, that is new to me

seancorfield04:01:05

You can create new data structures that implement ILookup and you can pass those as "arguments" to a keyword and it will "do the right thing". Clojure is about abstractions.

seancorfield04:01:03

user=> (def stuff (reify clojure.lang.ILookup (valAt [_ _] 42) (valAt [_ _ _] 13)))
#'user/stuff
user=> (:a stuff)
42
user=> (:b stuff :c)
13
(as a silly example)

solf05:01:25

I like this example, I've never used reify before nor extended a clojure implementation, but this gives me at least the very basics about why/how to do it.

seancorfield05:01:55

reify is awesome for adjusting one data structure to match another's API, so you can have different views into something. Also when you need to fake some interaction with Java under the hood.

seancorfield04:01:15

@codeperfect Does that example help illustrate the point I was trying to make?

Trevor05:01:31

Hey folks, I'm trying to interop with a Java library that leverages .class a lot, like below:

Family family = Family.all(PositionComponent.class, VelocityComponent.class).get();
Notice the PositionComponent.class I was hoping I could interop by doing the following:
(deftype MovementComponent [speed dir] Component) ; the lib requires that it extend Component 
; ... later in the code when I wanna make a family ....

; This doesn't work, get "Cannot cast class java.lang.Class to class [Ljava.lang.Class;"
(def fam (Family/all  MovementComponent) )

; Also doesn't work, same error
(def fam (Family/all (class MovementComponent)) )
So I'm worried I might have to make a new namespace for MovementComponent and use gen-class, is that true? Or is there something else I can do. Having to use gen-class would be a real bummer...

seancorfield06:01:10

@trevor670 So the issue here is Java varargs methods, not the classes.

seancorfield06:01:18

If you look at the Java docs for the Family/all method, I'm going to bet that is says static all(Class...) and what it is expecting here is an array of Component objects.

seancorfield06:01:37

So I think what you want is (def fam (Family/all (into-array Class [MovementComponent])))

Trevor06:01:16

I'll give that a shot!

Trevor06:01:17

YAAASSS, I t*h*ink it worked!

Trevor06:01:43

Thanks so much @seancorfield! This is super exciting! (Thanks for all your clojure contribs to!)

dpsutton06:01:47

the jvm is really weird but [Ljava.lang.class means an array of java.lang.class. Bizarre shorthand but the error message is trying to tell you

seancorfield06:01:28

@trevor670 What is this library BTW?

Trevor06:01:38

In gamedev there's a really nice pattern that's also cpu cache friendly called Entity-Component-Systems. Ashley is a java implementation that strikes a great balance between ergonomics and performance. ECS systems make let you break up your game logic into systems which apply functions to a set of entities based on what components they have. (Example: apply rendering logic to all entities containing a render component) They're not actually to hard to implement naively, but getting them performant is really important cause it's essentially your core game loop Which why this is so awesome! I get to use clojure where it matters and enjoy the performance of the Ashley ECS!

seancorfield06:01:32

Yep, Chris Granger, who created LightTable and Aurora, talks about ECS.

seancorfield06:01:44

public static final Family.Builder all(java.lang.Class<? extends Component>... componentTypes) so yeah, there's the Class... type for (into-array Class [...])

popeye06:01:12

I have installed intellj community edition and added cursive plugin , But I am not able to sync my file after starting repl,

popeye06:01:20

anyone faced same issue earlier?

seancorfield06:01:25

@popeyepwr Not sure what you're asking so maybe #cursive would be a good channel?

👀 1
Hagenek08:01:23

Is there an easier way to write maps like these in Clojure:

(defn createContact
  [phone email street city postal-code state country country-code]

  {
   :uuid "to be implemented"
   :phone phone
   :email email
   :street street
   :city city
   :postalCode postal-code
   :state state
   :country country
   :countryCode country-code
}
)

pavlosmelissinos08:01:22

You could use zipmap

(defn create-contact [vals]
  (-> (zipmap keys vals)
      (assoc :uuid "to be implemented"))
where keys is a vector of keywords that correspond 1-1 to the vals. This is not necessarily a better solution though, as you have less control over what goes in the map.

Hagenek08:01:16

Creative solution though, thanks!

Hagenek09:01:21

New question: (def contacts (atom [])) (swap! contacts (create-contact "" "" "Mellony Lane 42" "Berlin" "46162" "Berlin" "Germany" "52")) I then have this code, but I cannot get the info from the contacts atom in the repl? Tried this: namespaces.core> @contacts nil namespaces.core> contacts #<[email protected]: nil> namespaces.core> (str contacts) "clojure.lang[email protected]" namespaces.core> (str @contacts) "" namespaces.core>

Mno09:01:00

Does create-contact return the proper value?

Hagenek09:01:25

Yes, tested it in the repl

Mno09:01:48

Then try reset! Instead of swap!

Mno09:01:20

Sorry I just woke up, it's gonna take me a sec to start thinking

Hagenek09:01:51

No worries, it’s sunday after all:smile:

Mno09:01:47

yeah now that I look at it I believe you’re looking for reset! since you don’t seem to want to run anything ont he current value of the atom

Mno09:01:04

hopefully that helps

dpsutton09:01:38

i don't think your createContact function is doing any work. If you have 8 values, i don't see how a positional function helps you at all. just write the map there

dpsutton09:01:49

remembering the arg order seems worse than just constructing the map literal

☝️ 2
Hagenek09:01:48

Ok, so basically I am building controllers for a REST-api. Right now I am just going to populate it with mockdata. The reason I am creating a function is because I will have to also have a controller that creates a contact. I am very much a newbie though The thought now is to make a function that both creates a contact and puts it into the atom. This will later be connected to a DB

Mno09:01:38

ooooh i get it now

Mno09:01:55

yeah you can swap! it, but you have to specify how you wnt to update the atom so it’d be like :

(swap! contacts conj (create-contact "+47 935 35 312" "" "Mellony Lane 42" "Berlin" "46162" "Berlin" "Germany" "52"))

Hagenek09:01:57

ahhh of course! So that it knows to put it at the end of the list

Mno09:01:49

vector! but yeah!

Hagenek09:01:31

:uuid #uuid "7326bc03-d044-4b0f-bafc-da4daf91bff5", Gotten this value after using the Java.util.UUID lib. What does the #uuid mean in this context? Will it mess up my uses of the ID in someway going forward?

Mno10:01:00

I’m not good at explaining what tagged literals are

Mno10:01:30

but basically no.. you really shouldnt worry about it

roelof11:01:05

hmm, studying compujure but could not find one thing or Im overlooking it several times I want that if lets say the index page is hit, a method is executed and the end-result is send to the browser

roelof11:01:17

Does someone has a example for this ?

dumrat11:01:51

How about the usage example in the GH itself?

(ns hello-world.core
  (:require [compojure.core :refer :all]
            [compojure.route :as route]))

(defroutes app
  (GET "/" [] "<h1>Hello World</h1>")
  (route/not-found "<h1>Page not found</h1>"))

roelof11:01:45

Oke, I mean can I do things like this :

(defroutes app
  (GET "/" [] (display_data)
  (route/not-found "<h1>Page not found</h1>"))

dumrat11:01:35

@U0EGWJE3E Of course you can

roelof11:01:09

that is what I wanted to know

roelof11:01:33

I need 2 routes that uses I think the same method

dumrat11:01:02

btw, clojure names usually don't use underscores. Usually the use hyphen: display-data

roelof11:01:11

still does not display anything on my browser

(ns paintings.core
  (:require [cheshire.core :as json]
            [clj-http.client :as client]
            [compojure.core :refer :all]
            [compojure.route :as route]))


(defn image-url-size [image]
  (let [data (select-keys image [:width :height])
        url (get-in image [:tiles 0 :url])]
    (assoc data :url url)))

(defn take-image-data [image-data object-number]
  (->> image-data
       (sort-by :name)
       (last)
       (image-url-size)
       (merge {:object-number object-number})))

(defn assoc-image [object-number]
  (-> (client/get (str "" object-number "/tiles")
                  {:query-params {:key "14OGzuak"
                                  :format "json"}})
      (:body)
      (json/parse-string true)
      (:levels)
      (take-image-data object-number)))

(defn take-data [api-data]
  (->> api-data
       (map :objectNumber)
       (map assoc-image)))

(defn display-data []
  (-> (client/get ""
                  {:query-params {:key "14OGzuak"
                                  :format "json"
                                  :type "schilderij"
                                  :toppieces "True"}})
      :body
      (json/parse-string true)
      :artObjects
      (take-data)))

(defroutes app
  (GET "/" [] (display-data)))

Mno12:01:14

start by verifying that you get something useful back from (display-data)

Mno12:01:20

then verify that when your routes do something simpler they work. Try to rule out assumptions.

Mno12:01:58

for example test that when your routes are defined as:

(defroutes app
  (GET "/" [] "Hello World"))

Mno12:01:10

you actually get hello world.

Mno12:01:45

You can imagine it’s hard to guess what part of a computer is broken when it won’t even turn on…

(Is it the battery? the screen? the ram? is the power out? am I blind? is this actually not a computer? is it the GPU? maybe a flash chip? maybe something is shorting out? maybe this outlet doesn't work?)
see what I mean?

Mno12:01:18

I might also suggest you inspect your browser to see what html it’s rendering and also if it has any errors in the console.

roelof13:01:38

no luck. I think I forget the ring part

roelof15:01:47

nope, I do not see it

Mno16:01:51

simpler first, complex later.

Mno16:01:33

I can’t really be helpful when the problem is this vague.

roelof16:01:10

I think I have to add some code so I see the text

roelof16:01:19

so ring can make a server

roelof16:01:31

but I do not know how

roelof16:01:53

read some tutorials but still confused

Mno16:01:08

Like I said it’s hard to help when there’s so much I don’t know about your app, or what tutorials you followed

Mno16:01:29

I recommend you first try to follow something until you get “Hello World” or similar in your browser

Mno16:01:43

then try to edit it to use routes

Mno16:01:56

or if it’s simpler for you maybe try to start from a template.

clyfe21:01:54

(ring.adapter.jetty/run-jetty
 app {:port  3000, :join? false})
^ runs it

roelof21:01:41

yep, thanks, I now see the data that I want

roelof21:01:59

tomorow look if I can send the data to hiccup

Claudio Ferreira17:01:19

Clojurians, am i beeing too rude by only coming to this group when i have a problem? I was thinking about ways that i can generate value to the group itself, but i didn't found anyone. If someone have an ideia of how i can help all achieve your goals. I fell bad to only come here to extract.

dpsutton17:01:26

politely asked questions that lead to discussions help thousands of silent readers who may be facing the problem or just learn more in general. seems like a win win for everyone

💯 9
solf03:01:21

Everyday I learn new things from reading #beginners

Antonio Bibiano17:01:58

I'm doing an exercise from the brave and true which involves querying a list of search engines in parallel and returning the first result from each in a vector I came up with this

(defn search-online-all
  [query engines]
  (mapv (comp first deref)
        (doall (map (fn [engine]
                      (future (engine query)))
                    engines))))
The point of the exercise is to use future/delays/promises

Antonio Bibiano17:01:23

I was debating wether to use mapv instead of (doall (map ..))

Antonio Bibiano17:01:45

Or if there is a better pattern that could be used here

NPException17:01:16

One argument in favour of doall is that it makes it more explicit that you want to realize the entire sequence at this spot. Especially if you are working in a team it gives away the intention to other developers very clearly.

🙌 1
Antonio Bibiano17:01:13

ah nice! i liked it too

Antonio Bibiano17:01:50

I was also thinking if there is a nicer way to do this so that the first result is the one from the engine that returns first, the second from the second fastest etc..

Robert Mitchell17:01:59

You could put a vector in an atom to hold the results, and use swap! & update to conj each result as it comes in. A core.async chan would work too.

roelof17:01:23

hmm, 4clojure makes me crazy

roelof17:01:42

why is here % unknown in (reduce (fn [c _] inc c) 0 %)

Antonio Bibiano17:01:49

% only works in the #() macro

roelof17:01:08

Thanks, I hope this #(reduce (fn [c _] (inc c)) 0 %) is good clojure code to count a seq where you do not allowed to use count

Christian18:01:15

I think I solved it pretty mich the same way

roelof18:01:54

maybe i get the hang of it

🎉 1
Piotr Brzeziński19:01:07

Hey! I’m going through “Living clojure” and have ran into an issue when I was asked to install Cheshire. I added it to dependencies like so (project generated with lein if that matters)

:dependencies [[org.clojure/clojure "1.10.0"]
                 [compojure "1.6.1"]
                 [ring/ring-defaults "0.3.2"]
                 [cheshire "5.10.0"]]
then in my handler I try to require it like so
(ns cheshire-cat.handler
  (:require [compojure.core :refer :all]
            [compojure.route :as route]
            [cheshire.core :as json]
            [ring.middleware.defaults :refer [wrap-defaults site-defaults]]))
but when I run repl and try to use json/generate-string I get an error Syntax error compiling at….No such namespace: json how can I debug what could be going wrong here?

didibus19:01:21

Is your REPL in the user namespace?

didibus19:01:29

One thing that you need to understand is your REPL is not necessarily inside the cheshire-cat.handler namespace, and it is that namespace only where you have required cheshire as json

Piotr Brzeziński19:01:37

Ah, should it bee switched to the handler?

didibus19:01:54

So in user namespace you have not required cheshire as json and therefore can't use it

Piotr Brzeziński19:01:08

That makes perfect sense.

didibus19:01:12

Ya, you need to switch the repl to your namespace first

Piotr Brzeziński19:01:24

Too bad it wasn’t mentioned in the book. Would’ve saved me some frustration 🙂.

didibus19:01:33

No problem

didibus19:01:27

This can sometimes be a bit "magic", because some IDEs, like Cider, when you do eval-last-sexpr, it'll automatically eval it in the context of the namespace of the file you are in. So it might work like that, but then if you go at the REPL prompt and try to call something it won't. And it confuses people, cause you might assume that the IDE command to eval is the same as typing in the REPL but not exactly

👍 1
Piotr Brzeziński20:01:48

Right, got it. Thanks for the detailed explanation 🙂

Piotr Brzeziński19:01:21

I did restart the server so I assume cheshire was installed just fine.

roelof21:01:21

hmm, why here a classException #(reduce (fn [i xs] (conj xs i)) %) I try to reverse a seq but am not allowed to use reverse or rseq

Max Deineko21:01:51

In such a situation I'd try to check what the values of i and xs are with which the anonymous function gets called (additionally to @U11BV7MTK's suggestion below; I'd expect such a possibility to be useful in general)

didibus21:01:16

It helps to write it:

#(reduce
  (fn [accumulator element]
    (conj accumulator element))
  %)

Max Deineko21:01:31

+ if you prefer pen-and-paper style, also recall the difference between (reduce f coll) and (reduce f val coll)

roelof21:01:12

wierd, still the same error

roelof21:01:37

can it be that 4clojure uses a old version of clojure ?

Max Deineko21:01:15

"still" meaning when evaluating what code (and "same error" being what exactly)?

dpsutton00:01:22

(reduce (fn [xs i] (conj xs i)) () (range 6)) always use an initial value. otherwise reduce uses the first value of the collection for the accumulator

roelof08:01:31

oke, so I missed the initial value ?

Mno08:01:40

Try it out and tell us if it was that.. Learning to debug is arguably the most important skill to pick up.

Mno09:01:30

Open a repl and try it there with your own sample data, do a couple extra println just to see how the data changes.

dpsutton21:01:15

Your arguments to conj are backwards as are your arguments to the reducing function.

roelof21:01:15

then stilll the same error

dpsutton21:01:28

take some time and think about the arguments to your reducing function acc item. and take some time to think about the arguments to conj collection item and make sure they line up.

gibi22:01:40

Hi, I am learning reitit and this is an example copied from a book: https://paste.ofcode.org/WkTRZKPgrKZSJbSPBRXSpA when I try curl -X POST I get 404 instead of 405 though. It seems only the 404 default handler is considered :thinking_face:

didibus23:01:25

Looks like your parenthesis are wrong