This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-01-20
Channels
- # announcements (9)
- # aws-lambda (5)
- # babashka (26)
- # beginners (200)
- # bristol-clojurians (2)
- # calva (74)
- # cider (22)
- # clj-kondo (8)
- # cljsrn (1)
- # clojure (124)
- # clojure-australia (2)
- # clojure-europe (79)
- # clojure-spec (1)
- # clojure-uk (37)
- # clojurescript (87)
- # cloverage (1)
- # code-reviews (10)
- # conjure (41)
- # cursive (5)
- # datahike (2)
- # datascript (3)
- # datomic (11)
- # docker (4)
- # duct (1)
- # emacs (10)
- # events (1)
- # fulcro (3)
- # graalvm (1)
- # honeysql (3)
- # jobs (1)
- # malli (12)
- # meander (51)
- # off-topic (83)
- # pathom (28)
- # quil (3)
- # reagent (19)
- # reitit (3)
- # releases (1)
- # shadow-cljs (49)
- # spacemacs (2)
- # sql (5)
- # startup-in-a-month (1)
- # testing (1)
- # xtdb (8)
@mojitosmi If you click the ➕ next to Channels
in the left side bar, it lets you Browse channels
You can also try to just switch to a channel (control-k on Windows, cmd-k on Mac) and just start typing.
(I can't remember whether the "quick switcher" is enabled by default -- check Preferences > Advanced under Search Options
)
What's the recommended approach for dealing with dates and times in clojure? It seems like a bit of a mess. Should I stick with Java 8 APIs?
Either use Java Time directly or a wrapper like cljc.java-time or tick
Is it possible to mix Java and Clojure to implement some complex projects? I mean here is a Clojure open-source project, I need to reconstruct it, So which is the better way? Reconstruct completely by Java or by mix Java and Clojure?
@xu20151211 You can have a Java app that loads and calls into Clojure code, and you can have a Clojure app that calls into Java code.
See https://clojure.org/reference/java_interop for some examples/background.
When we first adopted Clojure at work (a decade ago now), we used it for low-level stuff and gradually replaced parts of our legacy applications -- so we had mixed language projects, calling into Clojure. Over time we rewrote more and more of them in Clojure.
Hello, is it possible to do something like this for spec?
(s/def ::plain-coord
(s/keys :req-un [::row ::col]
:opt-un [::sheet]))
(s/def ::merged-coord
(s/and
(s/keys :req-un [::first-row ::first-col ::last-row ::last-col]
:opt-un [::sheet])
#(<= (:first-row %) (:last-row %))
#(<= (:first-col %) (:last-col %))))
(s/def ::coord
(s/or :merged (s/keys :req [::merged-coord])
:plain (s/keys :req [::plain-coord])))
Or do I have to create a plain-coord?
and merged-coord?
to do the below
(s/def ::coord
(s/or :merged-coord merged-coord?
:plain-coord plain-coord?))
Like what I really want is to be able to do something like
(s/def ::coord
(s/or ::merged-coord
::plain-coord))
but it seems like spec does not work this way :thinking_face:there is both s/merge and s/or
it's unclear to me what you want or what doesn't work
one handy (undocumented) tool for use with s/or is s/nonconforming
Hmmm, I would like for :coord
to either take the the form of ::plain-coord
or ::merged-coord
in what way does it not work?
(s/def ::coord
(s/or :merged ::merged-coord
:plain ::plain-coord))
should work?if you're conforming, s/or will conform with the :merged or :plain tag which you likely don't want - in that case, wrap the spec in s/nonconforming. if you're just using s/valid? then it doesn't matter
just using s/valid?
but for subsequent reference, by wrapping you mean ...
(s/def ::coord
(s/or (s/nonconforming ::merged-coord)
(s/nonconforming ::plain-coord)))
?@zackteo (s/nonconforming (s/or ...))
as I recall...
It turns the whole s/or
part into a non-conforming spec, i.e., if it matches, it returns the original data structure.
yeah, wrap the nonconforming around the s/or
it conforms with the spec but returns the original value
user=> (require '[clojure.spec.alpha :as s])
nil
user=> (s/conform (s/or :int int? :str string?) 42)
[:int 42]
user=> (s/conform (s/or :int int? :str string?) "one")
[:str "one"]
user=> (s/conform (s/nonconforming (s/or :int int? :str string?)) 42)
42
user=> (s/conform (s/nonconforming (s/or :int int? :str string?)) "one")
"one"
we will probably have some kind of nonconforming or option in spec 2
I guess it also prevents similar conformance on any nested specs? (In the arms of the s/or
) Right, @alexmiller?
doesn't prevent, just ignores
it just conforms, then returns the original value
So you'd get a different result to flowing it through (s/conformer second)
(which would still preserve nested conformance and just erase the tag of s/or
)
Just something to be aware if you actually need some conformed values deeper in the data (which I've needed occasionally).
Hello, I was wondering about the difference between "first" and "peek". Would their results ever be different? Is there maybe a performance difference in some cases?
from the docstrings: first:
Returns the first item in the collection. Calls seq on its
argument. If coll is nil, returns nil.
peek:
For a list or queue, same as first, for a vector, same as, but much
more efficient than, last. If the collection is empty, returns nil.
Got it, thanks 👍
Note that peek returns the value at the insertion point (for stack usage) and for vectors that’s at the end, not the beginning
first is the correct function to use if you want the first element
except for PersistentQueue, which as designed peeks from the opposite end of its conj
(it's much more rarely used than lists and vectors though)
also, as I correct "seqs" to "lists" above - peek only works with stacks/queues, so doesn't actually work with things like lazyseq
Ya, peek is given a stack, returns the last inserted element. So its LIFO. first is given an ordered collection, return the first one from its order
And it seems that peek can also be: given a queue, return the first inserted element FIFO
Basically, it does something different based on the type of coll, so just make sure you are aware what type of coll you use it with
So my trick is: You peek from a stack or queue. And Lists and Vectors are also Stacks
Hi! Would that be a good solution to replicating items in a sequence?
(fn [xs count] (mapcat #(take count (repeat %)) xs))
it works but I’m trying to see if there’s a better way.Transducer option (slightly more verbose but a bit more “decomplected”):
(let [f (fn [xs cnt]
(transduce
(comp
(map #(repeat cnt %))
(mapcat identity))
conj
xs))]
(f [1 2 3] 3))
=> [1 1 1 2 2 2 3 3 3]Nice, I’ll save it for future reference since I’m not comfortable with transducers yet. Thank you 🙂
I don't know if it is better, but you could use #(repeat count %)
in place of #(take count (repeat %))
there to get the same results. Unless one is worried about optimizing run-time performance to the utmost, what you have and that small variation both seem like perfectly good ways to me.
Ah, nice, I thought repeat is a single arg function. That makes it easier to read for sure, thanks!
repeat
has 1-arg and 2-arg variants
Awesome. Thanks!
hmm, why do I get a server error when trying to read a css file
(defn create-image-element [{:keys [object-number width height url]}]
[:html
[:head
[:meta {:charset "utf-8"}]
[:title " Most popular paintings from the Rijksmuseum "]
[:link {:href "public/css/styles.css", :rel "stylesheet"}]]
[:body]])
A guess would be to remove the “public/” part. To test it you’d want to try and access the css file directly in the browser.
Typically a static file server points into a directory (often called “public”), while your root directory contains all the source code.
do you have a project.clj file or a deps.edn file?
yep, that looks like this :
(defproject paintings "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:url ""
:license {:name "EPL-2.0 OR GPL-2.0-or-later WITH Classpath-exception-2.0"
:url " "}
:dependencies [[org.clojure/clojure "1.10.0"]
[cheshire "5.9.0"]
[clj-http "3.10.3"]
[ring "1.8.2"]
[compojure "1.6.2"]]
:repl-options {:init-ns paintings.core})
You said you have a public/css
directory, is that in the project root, or is it in resources/public/css
?
It’s conventional to have resources/public/css
, and you may be libraries that are expecting that.
You might want to have a look at the “Static Files” section at https://learnxinyminutes.com/docs/compojure/
(I had to google that--I’ve switched from using compojure to using reitit, and I didn’t trust my memory of how compojure works.)
(defroutes app
(GET "/" [] (-> (display-data)
(convert-to-hiccup)
(hiccup/html)))
(GET "/favicon.ico" [] ""))
the normal thing is to have resources/public/css
and resources/public/js
etc. since resources is used for other things not just web assets
:thumbsup:
Hi Guys, I have no experience with a clojure, I have to add a new line into the clojure logic, I have a list of strings: "a", "b", "c" etc...
I need to return true/false if the following list contains a string equal to the op-name
variable.
If the list cantains the op-name
I need to return true, otherwise false.
Could you help me with a quick snippet for this. Will appreciate that.
some
could be a useful function for you. "Returns the first logical true value of (pred x) for any x in coll," So (some (fn [x] (= x op-name)) my-list)
would return whether that list had a member equal to op-name
Thank you guys, does the list of string should be a comma separated like
(some (set [op-name]) "a","b","c")
?
Also available options: (list "a" "b" "c")
, '("a" "b" "c")
, (vector "a" "b" "c")
All arguably less pretty
vector
, not vec
vec takes a coll
pure vs. referential transparency. Is it the same thing? This article is confusing: https://edward-huang.com/functional-programming/tech/programming/scala/2020/01/30/pure-function-vs-referential-transparency/
not a great article. its premise is that pure functions are a proper subset of referentially transparent functions. Then in an edit, the author says "If a function is referentially transparent, it is also pure." Probably not worth the time if the original was so off the cuff and probably good for #off-topic rather than #beginners
Hi folks - I’m a bit of a beginner, and I’m working on a project that takes a CSV file (through Java interop), does some processing on it, and exports the new file to [filename]-processed.csv
. I’m using https://github.com/clojure/data.csv/ and it works splendidly!
(with-open [reader (io/reader file-info) writer (io/writer new-file)]
(as-> (csv/read-csv reader) $
(map #(eval-line % header-info) $)
(csv/write-csv writer $)))) ; ALL THIS WORKS!
However, these are pretty big files, so the program takes about 15 seconds, and looks like the system locks up. Since I’m already using Java interop, I’d like to add a Java progress bar to show progress. However, I’m having problems wrapping my head around how I would implement it with the lazy processing above. Would it even be possible?I think you could decompose the problem into two parts: 1) calculating the progress and 2) reporting the progress. I understand you have something (ie. rendering a progress bar) in mind already for 2) above.
depending on what your processing needs are - sequential access is a lot slower, reducers are much faster.
For calculating progress (number of lines processed / number of lines in total), you'd need to know the number of lines in total when processing each individual line. You could perhaps make a first pass through the data to just calculate the number of lines if efficiency is not a concern; or perhaps you could figure out the number of lines to process via some other route. Then perhaps just process the data in batches matching some fraction of the total number of lines and reporting progress once per batch.
Oh, as hiredman also mentioned, you'd need to pass batches of data to write-csv for this to work, instead of trying to write the whole thing in one go.
I’ve written a defn to tell me the number of lines.
Then, perhaps something like
(doseq [batch (partition-all batch-size lines)]
(report-progress!)
(write-csv writer (map #(eval-line % header-info) batch)))
Yeah! I think doseq
is what I needed!
How would (report-progress!)
know what line we’re on, however?
Is there any way to get a counter on a doseq
?
`
(let [progress (atom 0)]
(doseq [batch (partition-all batch-size lines)]
(swap! progress inc)
(report-progress! (* @progress batch-size))
(write-csv writer (map #(eval-line % header-info) batch))))
Or perhaps
(doseq [[i batch] (map-indexed vector (partition-all batch-size lines))]
(report-progress! (* (inc i) batch-size))
(write-csv writer (map #(eval-line % header-info) batch)))
Thanks! I will try something like that!
use reduce (over a possibly partitioned set of data) instead of just passing all the data to write-csv
@hiredman Thanks about the as->
comment. I think I needed it at one point, now I don’t.
Hi! Is there any nice standard function for the use-case of "if expr is true, return expr otherwise return other"
(if expression
expression
(other-expression))
thanks 🙂
to easy
In a video Hickey alludes place oriented programming (even if it's update-in-place) is bad, what problems does PLOP cause?
Backus's 1977 turing award lecture "Can Programming Be Liberated from the von Neumann Style?" is trying to solve the problems created by plop, so it also describes those problems to some degree
> Conventional programming languages are growing ever more enormous, but not stronger. Inherent defects at the most basic level cause them to be both fat and weak: their primitive word at a time style of programming inherited from their common ancestor - the von Neumann computer, their close coupling of semantics to state transitions, their division of programming into a worlds of expressions and a world of statements, their inability to effectively use powerful combining forms for building new programs from existing ones, and their lack of useful mathematical properties for reasoning about programs.
thanks for sharing!
for one thing, it means you need to understand every function that has access to that place in order to understand the code
but as I recall he went into quite a bit of detail in that same talk
I think the main problem is "fragility"
@kaxaw75836 as a counterexample: when debugging clojure code, I can usually "capture" a value as it appears in a function, and then debug my code based on that value in isolation. In a C++ program that rarely if ever helps, and I need a stepping debugger to understand what happens to the places the function sees.
This is one of my favorite clojure advantage. Even if I know this is not an exclusivity
right, even in java you can snapshot some object out of a function to play with it in test code (in c++ this probably leads to a memory leak, or accessing freed data - place problems)
@noisesmith are you referring to immutability? or abstracting the machine?, if so is no different in JS or Python?
@kaxaw75836 I'm referring to the difference between thinking about places as the building blocks of code, vs. thinking of values as the building blocks
it's different than JS or Python because most JS and Python code still works in terms of updating hidden internal state, but those are still less place-bound than c++
By hidden internal state, you mean like some reference of a object that is pass around? or the runtime?
I mean that most code relies on objects with stateful internals (clojure has these too, but most of the core language is a set of tools for segregating states from values)
sorry, lost track of this yesterday I might have lost my point along the way here, but on further thought it really does come down to immutability (at least on the interface level). vectors and hash-maps do contain mutable internal state, but that's there because it has to be there, and a given object will give you back the same value every time you reference it. but, things like io streams and container types are there specifically to represent a state. that is, their utility is to provide access to something stateful, or create a stateful object over stateless internals) compare this to java / js / c++ where it's normal to have mutable private fields that actually do effect the behavior of the object, and many objects require specific initialization before usage - they are designed to mix state and value rather than separating them but I fear I've gotten too abstract here, and others might provide a better explanation than what I'm going for here (I was motivated to try answering this because I've been trying to go back to C / C++ lately but wanting to use them in a more fp way...)
@kaxaw75836 but this is a very general thing - it even applies to the difference between managing the contents of a tree of files (places) vs. data in a db (values with other values that describe their relations)
IMHO PLOP has two aspects that are worth considering. Like @noisesmith said, it decreases your facility for reasoning. Another aspect is increasing brittleness: code and data that change over time propagate changes to rigid structures around them.
talking about DBs, he mentions tables in RDBMS is also a place(bad) that creates coupling, and that documents are also a place that create coupling
@denis.baudinot right, in imperative place oriented code 90% of your code is ad-hoc inline adapters between ad-hoc data structures, this kind of thing doesn't even need to exist in clojure
@kaxaw75836 all programs have places, perhaps I picked a bad example, but this isn't a black/white thing, it's a way of guiding a design
The point is that you could use java with only immutable object and the place orientation of java is less an issue.
> Conventional programming languages are growing ever more enormous, but not stronger. Inherent defects at the most basic level cause them to be both fat and weak: their primitive word at a time style of programming inherited from their common ancestor - the von Neumann computer, their close coupling of semantics to state transitions, their division of programming into a worlds of expressions and a world of statements, their inability to effectively use powerful combining forms for building new programs from existing ones, and their lack of useful mathematical properties for reasoning about programs.
Clojure is not the only community that concerns itself with disentangling from PLOP. Game programmers have introduced Struct of Arrays, Data Oriented Design and Entity Component systems. They use data structures that are more relational and adaptive, mostly for performance reasons (CPU caching) but this has also a decoupling effect and generalises functionality. Frontend developers are shifting towards using frameworks like React etc., which have a clearer separation of state, data flow and rendering. The problems around PLOP seems to be unspecific to this community.
he also is critical of lambda calculus based programming languages, because he wants a more restricted basis to make things easier to reason about
the system he describes sort of sounds like coding directly in a combinatory logic like SKI, but less bare bones, which seems kind of like a nightmare
https://crypto.stanford.edu/~blynn/compiler/ may be of interest, it is a series of blog posts writing a haskell compiler and it goes haskell -> lambda calculus -> ski, it is very cool
hi what's your favorite way to do websockets or ajax in clojureland?
The only thing I’ve ever used for either is cljs-ajax and sente, and I’ve never had a problem, but I also haven’t worked in large projects with multiple people or tried out a lot of libraries… so might as well bring an entire salt lick for this piece of advice 😅
here's a question i've been wondering about for some time. in the java community (and others) folks will often favor so called "clean code". that can mean all sorts of things, so i'l be more specific. stuff like "one level of abstraction per function". decomposing functions into tiny helpers with "descriptive" names that hide the mechanical details of what you're doing. adding in domain concepts, in the form of function or object names, that hide the mechanical details of what you're doing. i'm in a clojure shop right now, having come from a java shop, and i'm finding that there is a high high tolerance for long functions with many levels of abstraction and few, if any, named helpers to express what you might call intent. just big expressions. stuff that would never have made it past code review at my last place. what do folks think? is there a deliberate preference for more inline, nested, low level expressions over extracted helpers with names? or is it just a tolerance thing? i'm very curious
there's a Martin Odersky talk (that i can't find right now) that expresses this well. he says, well, in scala, we have all these great abstractions and general purpose data manipulation functions (a la clojure). and so you could write a dense, multi-step transformation. but, according to Odersky, that would be a mistake because it would be too impenetrable for future maintainers.
@michael740 I would say that Clojure in general encourages small, pure functions, with good names, that isolation mutable state to the edges of the system -- but not all Clojure programmers produce such code, just like not all Java developers write "clean code".
There is no right and wrong here. http://number-none.com/blow/blog/programming/2014/09/26/carmack-on-inlined-code.html
this is an interesting essay. a lot of what he seems to be concerned about would be mitigated by pure functions, if i'm understanding this correctly
> Besides awareness of the actual code being executed, inlining functions also has the benefit of not making it possible to call the function from other places. That sounds ridiculous, but there is a point to it.... > > Strictly functional functions that only read their input arguments and just return a value without examining or modifying any permanent state are safe from these types of errors, and the nice ability to formally speak about them makes them a good ivory tower topic, but very little of our real code falls into this category. quite a lot of the clojure code i work on does indeed fall into that category
He also advocates for a functional style and its tradeoffs here: https://gamasutra.com/view/news/169296/Indepth_Functional_programming_in_C.php
come to think of it, brian will advocates for inlining helpers. he says it decreases the total surface area of the code base, making it more tractable.
Clojure advocates dsl which I find very close to language metaphor used in clean code
I think there is no point in putting things into defs that don’t need to be referenced. We have reader macros and a repl to evaluate/ignore things at the expression level
Structure is essential, but wether that structure is composed of function declarations is almost orthogonal to this
The "clean code" concept comes out of the culture of enterprise consultants. The clojure community is smaller, so it attracts fewer of those.
having said that, i usually write small functions, it comes naturally. But some functions are just large lists of doing things in sequence, explicitly, that are the kind of functions where keeping them large makes sense.
@denis.baudinot, as told in clean code, I find helpful to tell the intentions. Small functions help to do so
@denis.baudinot, even in the case you mention, I find helpful to explode in small local function, it helps readibility and testability . Maybe im too young in the language ...
again, I don’t really write a lot of large functions anyways. I’m rather against the notion that there should be some kind of limitation to this
if you haven't read elements of clojure yet (I am behind the times and haven't finished it yet), I don't think it mentions "clean code" by name, but it functions to some degree as a critique of "clean code" and similar stuff
i have read elements of clojure, yes. i'll revisit with that in mind
ztellman's(author of elements of clojure) last few days of tweets are him being annoyed that bob martin(author of some clean code book) exists and critiquing an exercise bob did
i can see that. bringing up "clean code" is a... hornet's nest, for sure
i'll check out the twitter.
Oh, yeah, that thread was pretty funny. Zach challenged Bob on (poor) naming choices and Bob was so condescending in response and then cut the discussion short. Bob doesn't like being challenged -- don't be like Bob 🙂
Ok here is a more specific follow up question: To build up application state, aka ‘load’ we usually do a whole bunch of plumbing in sequence, connect to a db, read some files, load in configuration… Should this be a large, single procedure, where the effects are explicit, in your face and the sequence of steps is clear? Or should this be composed of a abstracted, possibly data-driven configuration system? I think the first one is easier to understand and more “honest”, while the second opens up opportunities to build stuff that is about that process, which has operational benefits.
I think it depends. Sometimes you want a dynamic system where capacity and capability can change while the program is running. Sometimes you want a system that is mostly fixed and predictable. Sometimes you want a little of both. It depends on the use case.
I want to read the attributes of a file and for that I am using https://docs.oracle.com/javase/8/docs/api/java/nio/file/Files.html#readAttributes-java.nio.file.Path-java.lang.Class-java.nio.file.LinkOption...-
like this (Files/readAttributes (io/file "file-path") BasicFileAttributes [])
but I am getting an exception error: java.lang.IllegalArgumentException: No matching method readAttributes found taking 3 args
how can I represent java varargs in Clojure?
in this case you might want to use something like:
(Files/readAttributes (.toPath (io/file "file-path")) (into-array LinkOption [LinkOption/NOFOLLOW_LINKS]))
note that io/file returns a http://java.io.File but that method takes a Path
Hello
One question. How can I define a fixed set of values to a map attribute. Like an enum in java
Use set + spec and thats all? Nice
Use set + spec and thats all? Nice
in general, you usually don't need analogs to Java enums at all
either just use the constant values, or use :keywords for options (instead of public static final String blah). if you really need to collect them (for use of the full set somewhere), put them in a set or sometimes a map if there is ancillary info
or I guess a vector if there is some necessary ordering
you may be tempted to (def my-option :my-option)
- resist the urge, just use :my-option
Is there a function in Clojure to check if a number is in a closed-open range? E.g. a <= x < b
? I know I can use the expression (<= a x b)
, but that's a closed-closed range. I also know that I can use an and
to achieve what I want, but I would prefer something more succinct or more math-aligned. Any suggestions? Thanks
I'm considering defining a function <=<
that does that, but I'm guessing there should be something like this already done in core?