https://www.learnreframe.com/ Seems nice
Ah, sorry, missed that question. Yes, that's probably the one I would have recommended. There's also this one https://purelyfunctional.tv/courses/understanding-re-frame/ (and, yes, you need to pay for these).
The tradeoffs are very similar to Clojure vs Java. I would not build a library in Clojure that is consumed in a Java app unless I had some very specific and important reason to
interleave sounds very useful, but i seldom see it used
(def goof '(:a 1 š 2 :c 3))
(:a goof)
dumb icon face
i might expect an error from (:a goof)
(get :a goof) => nil
(get goof :a) => nil
that's at the cider repl
... or nil if key not present ... technically correct
loose typing
@codeperfect Is that a question?
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.
@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
Do you think it is "nonsensical code"?
get won't throw, it returns the key when present or nil
> Returns the value mapped to key, not-found or nil if key not present.
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
If you want it to throw, you should use the map as a function:
(goof :a)
This will help catch if you're not actually using an associative
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
It makes perfect sense once you understand Clojure's semantics.
(goof :a) is new to me
Because nil
-punning is core to Clojure's idioms. So returning nil
here is far more useful (and idiomatic) than throwing an exception.
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.
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
We have both approaches for different contexts.
yes that is the gist of it, i think the keyword function should only work with maps, that's all i am concerned weith
user=> ([1 2 3 4] 2)
3
oh, that is new to me
heh'
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.
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)@codeperfect Does that example help illustrate the point I was trying to make?
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.
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.
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...@trevor670 So the issue here is Java varargs methods, not the classes.
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.
So I think what you want is (def fam (Family/all (into-array Class [MovementComponent])))
I'll give that a shot!
YAAASSS, I t*h*ink it worked!
Thanks so much @seancorfield! This is super exciting! (Thanks for all your clojure contribs to!)
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
@trevor670 What is this library BTW?
I have installed intellj community edition and added cursive plugin , But I am not able to sync my file after starting repl,
anyone faced same issue earlier?
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!
Yep, Chris Granger, who created LightTable and Aurora, talks about ECS.
See https://www.chris-granger.com/2012/12/11/anatomy-of-a-knockout/ for example
And https://www.chris-granger.com/2013/01/24/the-ide-as-data/
@popeyepwr Not sure what you're asking so maybe #cursive would be a good channel?
Ah, here's Ashley: https://libgdx.badlogicgames.com/ci/ashley/docs/
public static final Family.Builder all(java.lang.Class<? extends Component>... componentTypes)
so yeah, there's the Class...
type for (into-array Class [...])
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
}
)
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.Creative solution though, thanks!
New question:
(def contacts (atom []))
(swap! contacts (create-contact "<tel:+4793535312|+47 935 35 312>" "<mailto:fixerman@gmail.com|fixerman@gmail.com>" "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
#<Atom@136cd01a: nil>
namespaces.core> (str contacts)
"clojure.lang.Atom@136cd01a"
namespaces.core> (str @contacts)
""
namespaces.core>
Does create-contact return the proper value?
Yes, tested it in the repl
Then try reset! Instead of swap!
Sorry I just woke up, it's gonna take me a sec to start thinking
No worries, itās sunday after all:smile:
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
hopefully that helps
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
remembering the arg order seems worse than just constructing the map literal
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
ooooh i get it now
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" "<mailto:fixerman@gmail.com|fixerman@gmail.com>" "Mellony Lane 42" "Berlin" "46162" "Berlin" "Germany" "52"))
ahhh of course! So that it knows to put it at the end of the list
vector! but yeah!
: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?
Iām not good at explaining what tagged literals are
so hereās https://clojure.org/reference/reader#tagged_literals
but basically no.. you really shouldnt worry about it
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
Does someone has a example for this ?
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>"))
Oke, I mean can I do things like this :
(defroutes app
(GET "/" [] (display_data)
(route/not-found "<h1>Page not found</h1>"))
@roelof Of course you can
oke
that is what I wanted to know
I need 2 routes that uses I think the same method
btw, clojure names usually don't use underscores. Usually the use hyphen: display-data
pfff
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 "<https://www.rijksmuseum.nl/api/nl/collection/>" 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 "<https://www.rijksmuseum.nl/api/nl/collection>"
{:query-params {:key "14OGzuak"
:format "json"
:type "schilderij"
:toppieces "True"}})
:body
(json/parse-string true)
:artObjects
(take-data)))
(defroutes app
(GET "/" [] (display-data)))
start by verifying that you get something useful back from (display-data)
then verify that when your routes do something simpler they work. Try to rule out assumptions.
for example test that when your routes are defined as:
(defroutes app
(GET "/" [] "Hello World"))
you actually get hello world.
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?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.
no luck. I think I forget the ring part
nope, I do not see it
simpler first, complex later.
I canāt really be helpful when the problem is this vague.
I think I have to add some code so I see the text
so ring can make a server
but I do not know how
read some tutorials but still confused
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
I recommend you first try to follow something until you get āHello Worldā or similar in your browser
then try to edit it to use routes
or if itās simpler for you maybe try to start from a template.
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.
Thanks @dpsutton!
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/promisesI was debating wether to use mapv
instead of (doall (map ..))
Or if there is a better pattern that could be used here
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.
ah nice! i liked it too
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
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..
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.
hmm, 4clojure makes me crazy
why is here %
unknown in (reduce (fn [c _] inc c) 0 %)
% only works in the #() macro
ah right!
thanks!
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
I think I solved it pretty mich the same way
š
maybe i get the hang of it
finally
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?I did restart the server so I assume cheshire was installed just fine.
Is your REPL in the user namespace?
It is, yes.
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
Ah, should it bee switched to the handler?
riiight
So in user namespace you have not required cheshire as json and therefore can't use it
That makes perfect sense.
Ya, you need to switch the repl to your namespace first
Too bad it wasnāt mentioned in the book. Wouldāve saved me some frustration š.
Thank you!
No problem
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
Right, got it. Thanks for the detailed explanation š
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
oke, so I missed the initial value ?
Try it out and tell us if it was that.. Learning to debug is arguably the most important skill to pick up.
Open a repl and try it there with your own sample data, do a couple extra println just to see how the data changes.
oke
Your arguments to conj are backwards as are your arguments to the reducing function.
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 @dpsutton's suggestion below; I'd expect such a possibility to be useful in general)
then stilll the same error
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.
It helps to write it:
#(reduce
(fn [accumulator element]
(conj accumulator element))
%)
+ if you prefer pen-and-paper style, also recall the difference between (reduce f coll)
and (reduce f val coll)
(ring.adapter.jetty/run-jetty
app {:port 3000, :join? false})
^ runs itsee this if you haven't yet: https://skillsmatter.com/skillscasts/3445-functional-web
wierd, still the same error
can it be that 4clojure uses a old version of clojure ?
yep, thanks, I now see the data that I want
tomorow look if I can send the data to hiccup
"still" meaning when evaluating what code (and "same error" being what exactly)?
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 <http://localhost:3000/echo/4>
I get 404 instead of 405 though. It seems only the 404 default handler is considered :thinking_face:
Looks like your parenthesis are wrong