This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-06-21
Channels
- # announcements (3)
- # aws (11)
- # babashka (5)
- # beginners (116)
- # cider (30)
- # clara (1)
- # clj-kondo (15)
- # clojure (17)
- # clojure-dev (9)
- # clojure-europe (2)
- # clojure-italy (1)
- # clojure-uk (3)
- # clojurescript (9)
- # conjure (3)
- # duct (22)
- # exercism (1)
- # fulcro (8)
- # graalvm (5)
- # graphql (3)
- # helix (3)
- # joker (3)
- # kaocha (2)
- # off-topic (9)
- # pathom (4)
- # re-frame (1)
- # rum (6)
- # shadow-cljs (81)
- # sql (6)
- # xtdb (9)
Needed to add float
(def average (float (/ (+ 20 50 60) 3)))
float is only needed for interop (and even then is very rarely needed) - use double
, and also you can count on the result being floating point if 1 arg is floating point
I generated a new Leiningen project and am trying to run it using lein run but am getting the following error: No :main namespace specified in project.clj.
I created the project in Cursive, then I had been running it in the REPL
Then I opened a command prompt and typed lein run in the project dir
weird. i wonder what cursive did.
/tmp ❯❯❯ lein new app thing && cd thing && lein run
OpenJDK 64-Bit Server VM warning: Options -Xverify:none and -noverify were deprecated in JDK 13 and will likely be removed in a future release.
Generating a project called thing based on the 'app' template.
OpenJDK 64-Bit Server VM warning: Options -Xverify:none and -noverify were deprecated in JDK 13 and will likely be removed in a future release.
Hello, World!
That's really odd, creating a project through the command line worked
File--> New Project --> Leiningen
looking at the non cursive project
:main ^:skip-aot learn.core
is inside project.cli
you can specify a template to be used. i put app
in the template spot and it does what the command line version does. hope that helps
What's going on under the hood when (seq [1 2 3])
is called? The https://clojure.org/reference/sequences suggests that seq
returns an implementation of ISeq
that "appropriate to that collection", but if that's the case why does (conj (seq [1 2 3]) 0)
append to the left rather than the right, which would be the most performant way to append to a vector?
"appropriate to that collection" means it returns a seq that knows how to traverse that collection, not some kind of seq that is different
https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/APersistentVector.java#L446 <- this is a seq that is "appropriate to that collection" for vectors
its correct when you know what's going on but is understandably confusing when reading for the first time
@abhiyantsingh This might be good reading, as it talks about the differences between "collections" and "sequences" http://clojure-doc.org/articles/language/collections_and_sequences.html
Got it. Appreciate all the replies! One example I'm curious about is (-> [1 2 3] (conj 4) (seq) (conj 5)) => '(5 1 2 3 4)
. In this situation, conj
adds to the right of the vector
but to the left of the seq
generated from it. Based on the code that @dpsutton linked, it seems like seq contains references to the original vector, does that mean that any conj
calls to a seq made from a vec are O(n)?
hiredman put it very well. it knows how to traverse a vector quickly. but you have a think with two functions on it: first and rest. and the only way to add is to put something as the new first
Once you call seq
on a vector, you get a "chunked seq(uence)" and conj
on a sequence acts like cons
so it prepends the new item.
You can see some of the types in play here
user=> (type [1 2 3])
clojure.lang.PersistentVector
user=> (type (seq [1 2 3]))
clojure.lang.PersistentVector$ChunkedSeq
user=> (type (conj (seq [1 2 3]) 0))
clojure.lang.Cons
user=> (type (conj [1 2 3] 0))
clojure.lang.PersistentVector
user=>
if your view of the world is the first thing and then the remaining things, the only way to add quickly to it is to plop it as the new first.
(also, from the above types, you can perhaps infer that (conj (seq [1 2 3]) 0)
is O(1) because it simply returns a Cons
object with 0
as the first
and the original sequence as the rest
)
So is the cost of calling seq
on a vector O(n)? Because it has to create the ChunkedSeq? It seems like there's a traversal happening in the constructor there in arrayFor
so just wanted to confirm.
So, based on @seancorfield's example, it constructs a ChunkedSeq, and my interpretation of the code https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/PersistentVector.java#L373-L378 is that it's doing a traversal; am I misinterpreting what's calling what?
I suppose what I'm struggling with is that if you start with a vector and end up with an operation that appends to the left side, such as (conj (seq [1 2 3]) 0)
, I don't see how an O(n) operation is avoided, since you either append to the left of the vector, which is O(n), or spend O(n) to build a collection that has O(1) left appends. Does that make sense?
you don't append to the left of the vector in the sense that the vector is now [0 1 2 3]
. you append to the left of the seq in the sense that you have 0 first and the rest is a seq view of the vector
the chunked stuff and reading the java code can often introduce more complexity when first learning it. so i hope i didn't muddy the waters too much
Not at all, the concreteness helped! I'd been poking around the code base for the last hour trying to figure this out but was looking in the wrong places.
If you are poking around the Java implementation of Clojure to learn, then you might in some cases find this library useful for visualizing the in-memory representation of Clojure values as JVM objects: https://github.com/jafingerhut/cljol
as did i. i went right to APersistentVector
and sean did a very thoughtful thing and asked the repl what is actually going on
I still get a little muddy understanding how IPersistentVector
, APersistentVector
and PersistentVector
interact. but those concerns are far from #beginners channel 🙂
Hi all! I am getting started with clojure (with some javascript experience) and quite love it, though am having difficulty figuring out the app-packaging side and wondering if anyone had advice/or a good direction to point me.
In short: I am building a daily-update page using clojure and hiccup…it reads some weather info, plus an .edn file I made of my feelings and observations I’d made about weather that day, and translates it into a single static html page.
I made this with using lein new app
and it works well enough, but where I am lost is how to add new feelings/observations. I was imagining a simple terminal interface that just said “how you doing!” then “how’s the weather?” and takes the input from both these lines and writes them as a new map to my feelings.edn, and then run the page generator and take the top map from this vector to update the page.
I’m finding it hard to conceptualize how to make this simple terminal interface…of essentially printing “What is your feeling: ” and waiting on text input. On searching online I found a cool looking [cljs-tui](https://github.com/eccentric-j/cljs-tui-template) template plus [lanterna](https://multimud.github.io/clojure-lanterna/4-reference), but felt that both might be overkill for what is a simple ask?
(part of this is that I’m coming from javascript experience of looking for a framework first, then making that work for my needs…and trying to get away from that)
clj -e '(println "how are you feeling?")(let [feeling (read-line)] (spit "feelings.edn" {:feeling feeling}))'
oh, awesome, thank you, @dpsutton! Do you think the best way to do a two-step question (e.g. “how are you feeling”->input, then “how is the weather?“->input) be to define a map of {:feeling :weather}, then do a print statement for feeling, assoc read-line to :feelings, then second print for weather, assoc read-line to :weather, then spit that map to feelings.edn? This feels like a straightforward /imperative way to do it, but not sure if it’s idiomatic.
I think that’s ok:
(let [_ (println "how are you feeling?")
feeling (read-line)
_ (println "how's the weather?")
weather (read-line)]
(spit "feelings-and-weather.edn" {:feeling feeling :weather weather}))
Seems to work inside a clj repl, for some reason doesn’t work via the “clj -e” commandHello everyone i am vishal ,i am a freelancer i offer services in web development,app development,SEO.I will provide services at lower prices without compromising the quality of product. Dm me if anyone has any project.
Anyone who knows some resources to compile ClojureScript using GitHub actions?
Just a curious question... in Java it is possible to represent larger numbers with using underscore like this: 1_000_001
so it's more readable and actually writable. Is there anything similar to this in Clojure?
The Clojure reader does not support that, no. One could write their own code/data reader that does, but that would not help you write numbers in that way in an unmodified version of Clojure.
@andy.fingerhut do you think it's realistic to request such improvement? It's obviously nice to have, low priority thing, but still...
I suspect it already has been requested -- checking to see if there is a JIRA issue for it already. I don't expect such a change to make it into Clojure soon, if ever. It isn't pure advantage -- consider the use case of searching for occurrences of the number '1000000' in source code using tools like grep.
I didn't find an existing issue in a minute of looking. You are welcome to ask the question on https://ask.clojure.org yourself and see what kind of response you get.
Understood completely. I am not against it myself. But neither am I the decision maker, and it isn't a democratic process.
(nor do I think it should be a democratic process)
I've found this https://ask.clojure.org/index.php/8511/add-digit-separators-support-to-number-literals?show=8511#q8511 I actually give it a short and did some implementation myself. TL;DR I have a working implementation, working on tests. I'll try to be initiative and propose a patch with some rationale and pros and cons as I see them.
Cool. I didn't see any comments from someone like Alex Miller in that http://ask.clojure.org conversation, for or against the proposed change. That simply means there is no information there on whether the Clojure core team is interested in such a change. It is at least possible that they are not interested, but haven't mentioned it in that issue. If you enjoy making experimental patches for the sake of your learning, great, but if you are becoming strongly emotionally invested such that your world view will change if they say "no" to the idea, you may want to get some indication of that before spending lots of time on it.
How do I make this work:
(contains? (sort #{2 1 3}) 1)
It gives me contains? not supported on type: clojure.lang.ArraySeq
yeah, that's just an example. In reality my set/arrayseq is coming from (sort (java.time.ZoneId/getAvailableZoneIds))
could you have a sorted version of it for iteration and a set for membership checking?
yeah, sure. I thought there was a simpler alternative for contains? that works with arrayseq
arrays can only check membership through linear scans checking each element for equality. keep a datastructure that has O(1) membership check and a version that is an ordered version if you also need that
the docstring of contains?
points you towards some
if you do need to search through an ordered collection for an item
i point that out because (doc [thing])
is an incredibly useful thing. the repl is self-documenting to a large extent and very helpful. your editor most likely has some keybindings and UX to ease this as well
I've been using http://clojuredocs.org for the accompanying examples mostly, will give doc a try
http://Clojuredocs.org contains output of doc at the top, before the examples
@somedude314 what editor are you using?
At least for things that http://clojuredocs.org covers. It does not cover many Clojure libraries, if any
https://cursive-ide.com/userguide/documentation.html#clojuredocs-support if you don't already have them setup
yeah. i think those are bound by default to the same keybinding. not sure. but i think you're seeing what i was suggesting
Am gonna roll with this then:
(defn timezones
[& {:keys [sorted?] :or {sorted? false}}]
(let [tz (java.time.ZoneId/getAvailableZoneIds)]
(if sorted?
(sort tz)
tz)))
This makes me wonder how many over complications I have in my Clojure code as a beginner 🙂
A good rule of thumb is for functions to do one thing only: a function to return the timezone IDs, a function to sort them. The latter is built-in. Small, composable functions, mostly pure.
If I would like to provide a different implementation to a java method like isEmpty
to my custom record, how should I approach it?
(defprotocol IMyInterface
(isEmpty [this]))
(defrecord MyData []
IMyInterface
(isEmpty [this]))
The above code will not work with the following error msg: Duplicate method name "isEmpty" with signature "()Z" in class file
@iagwanderson Records already implement .isEmpty()
based on whether they have any fields or not:
user=> (defrecord Foo [])
user.Foo
user=> (.isEmpty (Foo.))
true
user=> (defrecord Bar [x])
user.Bar
user=> (.isEmpty (Bar. 42))
false
user=>
I noticed that, I was following a java example where the property of being empty for a specific class had a custom definition. I wanted to implement the same and found this "problem"
I know I could change the name but I got curious about how to go about "overwriting" the default implementation
Changing the definition of isEmpty
on a record could break all sorts of things in Clojure operations on it, I suspect.
I think you'd have to use deftype
and build up a map-like data structure from scratch in order to provide custom isEmpty
behavior... which would be a lot of work and also produce a custom data structure with "unusual" behavior...