This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-06-06
Channels
- # beginners (137)
- # cider (60)
- # cljs-dev (52)
- # cljsrn (5)
- # clojars (15)
- # clojure (156)
- # clojure-brasil (1)
- # clojure-dev (7)
- # clojure-italy (13)
- # clojure-serbia (2)
- # clojure-spec (12)
- # clojure-uk (76)
- # clojurescript (129)
- # core-async (27)
- # core-typed (1)
- # cursive (3)
- # datomic (105)
- # devcards (39)
- # emacs (10)
- # figwheel (1)
- # fulcro (68)
- # graphql (6)
- # juxt (3)
- # klipse (85)
- # lein-figwheel (47)
- # leiningen (3)
- # midje (1)
- # mount (26)
- # off-topic (71)
- # om (4)
- # overtone (4)
- # parinfer (3)
- # pedestal (4)
- # portkey (37)
- # re-frame (37)
- # reagent (13)
- # reitit (3)
- # ring (1)
- # rum (5)
- # shadow-cljs (191)
- # spacemacs (35)
- # specter (26)
- # tools-deps (45)
- # vim (20)
Hello everyone, I have a question that appears here at least twice a day (maybe time for the pinned post?)—how to get started with Clojure. I’ve actually checked out few guides on how to start but would like to still hear how you all started.
I’m proficient in Node.js (also done some infrastructure project in Python 3) but am tired of imperative
Right. I mean Node.js is still a great prototyping platform for me, but for long time I’ve been telling myself “there must be a better way” and Rich Hickey seems to address all of those issues in his talks (using Clojure) 🙂
$ clojure -Sdeps '{:deps {org.clojure/clojurescript {:mvn/version "1.10.238"}}}' -m cljs.repl.node
ClojureScript 1.10.238
cljs.user=> (clojure.string/upper-case (-> (js/require "fs") (.readFileSync "foo.txt") (.toString)))
"HELLO WORLD\n"
cljs.user=> (map {"H" "H", "E" "O", "L" "L", "O" "O", " " "W ", "W" "W", "R" "R", "D" "D", "\n" "\n"} *1)
("H" "O" "L" "L" "O" "W " "W" "O" "R" "L" "D" "\n")
cljs.user=> (apply str *1)
"HOLLOW WORLD\n"
cljs.user=> (-> *1 (clojure.string/lower-case) (str "!!"))
"hollow world\n!!"
:~)However I learn the best by actually making useful stuff—unfortunately, most of the Clojure guides seem to focus on trivial algorithms, not on building in practice
Do you know any resources that focus mainly on building Clojure knowledge by actually making some small but useful apps? Preferably (but not necessary) video format?
Btw. http://PurelyFunctional.tv has a good tips on side projects: https://purelyfunctional.tv/functional-programming-career-guide/10-side-projects-resume/ I did this one as an example: https://curiousprogrammer.net/2018/05/11/pureblog-a-simple-blog-implementation-in-clojure-for-purelyfunctional-tv/
Programming Clojure and Clojure Applied @radekdymacz
i started by watching Simple Made Easy and some stuff on YouTube like https://www.youtube.com/watch?v=VVd4ow-ZcX0
I’m basically looking for something that’ll get me be somewhat comfortable in the language and project setting and from there I’ll be able to go on my own
those two books i recommended should do that, lots of people also start with Web Development with Clojure
the only video course i'm aware of is https://purelyfunctional.tv
@radekdymacz there's also https://lambdaisland.com/episodes which is cheaper but http://PurelyFunctional.tv is much more curated and more complete I'd say.
Tim Baldridge also has some Clojure Tutorials: https://tbaldridge.pivotshare.com/ Again, perhaps not that interesting for a complete beginner. But good for learning particular aspects of language (transducers, core.async, etc.)
@kyselyradek does https://purelyfunctional.tv/learning-paths/ match what you were looking for?
@kyselyradek Perhaps also look at https://pragprog.com/book/dswdcloj/web-development-with-clojure
Oh, there's a second edition! https://pragprog.com/book/dswdcloj2/web-development-with-clojure-second-edition
(I haven't read it but a lot of people seem to follow that book's path to get started writing web apps in Clojure)
My path was... unusual... I did Lisp at university in the early 80's and then a PhD in Functional Programming Language Design & Implementation... so when I started Clojure, it was more of a "home coming", and I started with The Joy Of Clojure. It's more of the "why" of Clojure rather than a beginner's book, but I think it makes a really good second or third book...
What sort of apps are you interested in building?
Actually, now that I’m looking at the table of contents, it seems kinda helpful, you use web-based protocols for multiple applications
I'm purely a server-side dev too.
I build REST APIs and occasionally a small app with actual HTML web pages but mostly backend process stuff.
Okay, thank you guys for your recommendations, I will check those out 🙂 Sundar, I didn’t know about that “Learning Paths” playlist, I just can’t navigate that website 😂
Hello everyone, question about managing state.. building small SPA where client initate websocket then server Pull data from some apis and push to the client on schedule, wanted to make the API querying happen only if theres clients connecred so found my self keeping track of ws connections count in an atom int and Inc and dec that count whenever new ws open/close, my question is Is there other technique or idiom to deal with this kind if state with less mutating functions or it's normal use case to store state in global atom in namespace and let functions mutate it
That is fairly common, though folk would advise to write mostly pure functions, and keep the impure functions that mutate the system atom to a small handful of top-level action functions. If your state gets big enough to become confusing, there are libraries that offer various approaches to managing it. Depending on your server impl, you could keep your system atom in a closure instead of a var if you like.
Oh, and it’s possibly neither here nor there but you may find using a set instead of a counter more useful, if your websocket thingies have a stable identifier
Thank! keeping atom in closure is an option I have not tried before , will look into what library available, definitely felt with more complexity there must be more functional way or way of re-org things to better manage states
Component, immutant, and mount are the three libs people talk about the most, but I wouldn’t reach for them before you need to except for inspiration or comparison
Hello everyone, I am Gavin! I am new to Clojure. I am working on a simple Clojure 1.9 project. It was configured with a minimal .travis.yml to build on Travis. The build failed on OpenJDK 9 but not other JDK environments. Anybody knows why? Thanks!
@me1673 Java 9 brings some challenges for Clojure -- which have mostly (all?) been addressed in recent updates to Leiningen/Boot etc. So it may be that you're not getting a recent enough Leiningen version on Travis?
Hmm, security stuff...
@seancorfield Thanks for your help! I have tried Leiningen 2.8.1 but no luck. Moreover, it works with OracleJDK 9.
Ah, OK.
Am I reading your project right that it's all the Clojars artifacts that won't download -- but the Maven artifacts download just fine?
Hmm, so that suggests a certificate issue between OpenJDK9 and Clojars -- maybe go ask in #clojars and see if anyone there knows what might be up.
Sorry I don't know which side might need changes there. JDK/certs stuff is a black art 👀
I moved my transducer exercises to Github and added all the solutions too. https://github.com/green-coder/transducer-exercises
@seancorfield I see, thanks Sean! 😂
Yay! https://github.com/ir-regular/okasaki-clj Thank you for help and ideas @noisesmith @dpsutton @yogidevbear 🙂
Currently my function makes 2 rest calls, since the last expression is a rest call, this is exactly hat is returned. I want my function to return nil, what should I do? Add nil as the next expression? That seems kinda ugly Example:
(defn my-fn []
(rest/x)
(rest/y))
@denisgrebennicov Why do you need the function to return nil
? If the function is just doing side-effects (calling REST APIs) then it's caller can just ignore whatever it returns...
@seancorfield it doesn’t necessarily have to return nil
, but I was thinking that this might be good idea.
Unless you're specifically returning a value that you expect the caller to care about, I wouldn't worry much.
I guess I might, at that point, be more concerned that you're just throwing away the results of the REST calls 🙂
It was just irritating to see all the REST call result, when calling the method in the repl
@denisgrebennicov Fair enough. I'm not sure what the idiomatic approach would be there. I guess (when (my-fn))
is as good as anything...
If you're getting back some sort of collection or sequence, dorun
is probably more idiomatic? (dorun (my-fn))
but it expects to be able to call seq
on that expression and next
to walk all the way through it.
I kind of wish the do
verb had been reserved for “side effects only” instead of “unlazify”
@lee.justin.m how would you write the equivalent of (do (f1) (f2) expr)
then, where you wanted some side-effects and then a value returned?
I haven’t really thought this through, but generally I think the highest utility in naming a function is explaining what it returns / how to use it. I.e., it’s nice to be able to distinguish between a side-effect-only function, a function that returns a lazy result, and in cljs, a function that returns a promise or a channel. It’s probably not possible to encode too much, but, still, at least with laziness I regret that there’s not a convention for “this is lazy” instead of using do
for “this makes thing unlazy”
so for a function that side-effects and returns a value, i’m not sure i’d name it anything in particular at all
also incase i wasn’t clear, i don’t mean the special form do
, i mean using do
in function names
I figured, but wanted to check. I think of do...
as an imperative, rather than anything to do with laziness.
I’m working with spec right now. Want to catch/parse the value which ends with * (for my regex parser)
Currently something like this doesn’t work -> (s/cat :base ::base :star #"\*")
Any ideas? The regex matchign doesn’t seem to work and I don’t know how to make string match in spec.
@denisgrebennicov you need to escape an asterisk.. maybe \\* ?
@denisgrebennicov spec is not designed for parsing strings.
you can use re-seq
to make a predicate matching a string regex
EU residents: Where did you get your Clojure books from? (mostly Programming Clojure and Clojure Applied) They’re either out of stock in EU or have insane delivery fees from U.S. (like higher than the book price)
I’ve so far heard mostly this wrt obtaining these in the EU unfortunately
I’ll ping my prag contacts and see if they have any advice
The Pragmatic ones are DRM Free in epub, mobi, and PDF format. (You get all three) It's really nice. I can use iBooks, Kindle, or something else.
e-ink kindle?
because those are very kind on the eyes
is there a good rule of thumb or example regarding how to separate out pure function vs side-effect functions? The concept of pushing them to the edge is nice, but in practice, the codebase gets contaminated pretty quickly, and i have to constantly think if I need to add a doall
before each pmap
because the actual side effect function could be many level below the immediate pmap
'd function. This also results in most of the tests needing to do with-redefs
etc.. It's hard to describe but it kind of feels like writing Java in clojure.. It would be really helpful if there's a medium to large scale code base that deals with DB access and HTTP requests in a clojure way.
Re: ebooks -- I pretty much only ever buy PDF versions of books these days. I keep them all on OneDrive and read them on my iPhone, my laptop, and my desktop. Guess I've gotten used to it, but I buy a lot of pre-released versions and it's nice to see how they evolve into the finished product. I think I have about 100-150 tech books on my iPhone now...
why have i never thought of this, that is so much easier than manually copying books from computer to phone. you're a genius
@blance pmap
seems attractive but it's a bit of a sledgehammer (and it sounds like you're already starting to experience some of the downsides?).
It's hard to completely separate out pure and non-pure functions in real world apps but, as much as possible, try to do all of the "queries" you need upfront, pass all that data into your pure functions, and have them return a set of changes that need to be persisted externally.
That can get pretty complicated -- so you have to compromise to keep your code readable sometimes.
Something that you can do is define protocols for the APIs of the external systems you need to interact with and then you can easily write a stub implementation for testing. Stuart Sierra talks about that with his Component library. I think he did a talk called Clojure In The Large which covered that sort of thing.
https://www.infoq.com/presentations/Clojure-Large-scale-patterns-techniques from Clojure/West 2013
An earlier version of the talk from a user group in NYC https://vimeo.com/46163090
I've been working with clojure in production for 1.5 years, but the code base I'm working on still feels not right.. side effects are everywhere, I can hardly write any test without stub. like I mentioned earlier, it just feel like writing java in clojure syntax.
Yeah, our early Clojure code was a bit of a mess -- stateful singletons and other horrors. Still slowly digging our way out from under parts of that.
I mean, be liberal in what you accept, and conservative in what you do, or however it goes
I would generally agree (but do find it useful as a quick solve for some chunky problems)
with-redefs
in tests is also a bit of a red flag, in a well put together system you should be able to pass in a different argument for whatever to get a different behavior. you have to be careful combining with-redefs and any kind of concurrency
if I remove all tests that needs with-redefs, I would only have 5%~10% left:joy:
I get the concept for the most part, but sometime passing as arguments would mean it would be passed around all over the place, and i'm not sure if it's a good practice to let intermediate level knows all the details that only upstream/downstream cares
For example, if I have a call chain A->B->C->D, where D needs some data
from external source. would I fetch it in D, or fetch it in A and pass all the way down?
If you abstract "external source" into a protocol and an implementation, and pass it (as part of a "system" map) through that call chain, then D would call a method on that source to get the data. That would at least allow you to create a mock implementation of that protocol and pass it in for testing -- so you could control what D got from the source.
But, as others have indicated, if you can do the "external source" stuff at the top and pass it into the whole chain, your life would likely be less painful.
If you start to practice that, then D would never get written to pull data from an "external source" in the first place, since D would expect to be passed its data as an argument.
(and, yes, this can be really hard in programs that interact with databases -- unless that database is Datomic and you can treat it as an immutable value 🙂 )
We certainly have plenty of stuff at work where call chains like this exist and D reads from (and sometimes writes to!) the MySQL database. We regret that approach now.
Also similarly I assume for writing to external resource, D would return the data all the way back to A and A then calls E to write out?
But wouldn't that violates DRY? if A' also wants to write, then it needs to get from D then Calls E as well
Like several have said, separate all external reads and all external writes and keeping them out of your pure code and just doing them at "the top" is hard. Possible, but hard. Often it requires completely rethinking how you would approach a problem. There's no One True Way and you'll generally have to make some trade offs.
I'm not sure what you mean about passing mutable variables in from the top -- mutable variables are extremely rare in Clojure.
One problem you can run into with trying to completely separate out reads, processing, and writes can be seen in a library I wrote and then sunsetted after I'd tried using it in production code: https://github.com/seancorfield/engine
The resulting code can look very "monadic" which is not at all idiomatic Clojure:
(-> app
;; indicate desired updates
(e/update :user {:id 9 :username "nine"})
(e/update :user {:id 10 :username "ten"})
(e/delete :user 11)
(e/update :ram :name "Sean Corfield")
;; indicate intended result
(e/return 42)
;; commit changes
(e/commit!))
;; returns the result and applies the updates
and this indicates that the way of thinking about the problem is incorrect.Part of the problem there is lower-level code trying to describe the shape of the changes that are needed to external systems -- you end up with a domain specific language and an interpreter, which is much more complicated than the problem you started out trying to solve. Sometimes the solution can be to break the problem into smaller pieces and then combine those in a pipeline (so the reads/writes are at the top-level of the pipeline and all the pure processing is done in between). Sometimes you can leverage core.async as a way to "produce" data/changes from code, where there is a separate consumer that does the writes -- passing the "output channel" into the otherwise pure functions (and then, for testing, you write a mock consumer that can verify the expected data ended up on the channel).
For example, we have a sitemap generator process. It reads data from MySQL, processes it, and sends the processed data to various channels (that are created up front and passed in), then there are consumers on those channels that write the processed data out as XML. For testing, we can provide "canned" data instead of a database and we can consume the channel data and verify it is appropriate.
(our actual process is more complex and can't quite be tested that way -- but that's mostly because I didn't spend a bit more time thinking about it before I wrote the code!)
Hope that helps?
This is very helpful, especially the channel part. I think I'll need some time to process these and try to refactor part of our code base to see it in action. Thanks a lot for these!
I wish I'd gotten into core.async long ago. It's hard to get your head around, but it really can help decouple things.
if possible can you give us some sample code describing the solution for the above mentioned code with or without async? Thanks
@U8Y8U7SLS The only code I have that really shows this stuff off is work-related, so I can't share it I'm afraid. Sorry.
there is no simple answer to that question
but in general I would try to separate <code that talks to external stuff> as much as possible from <code that uses data>
and having anything stateful / side effecting / talking to the outside world deep in the call structure is a code smell in Clojure - everything gets a lot simpler if i/o and state is as close to the top of the call-chain as possible
so then the only things getting passed deep are immutable values, which are much less dangerous to share
Hello 🙂 If I do the following, I'll end up with a symbol. What can I add to get a name instead, so that I can call clojure.repl/doc
on it? (My goal is to get all the fns in a namespace that have a particular signature. It's possible there is a better way entirely...)
(->> some.namespace
clojure.repl/dir
with-out-str
clojure.string/split-lines
first
read-string)
Look at the ns- functions to start with data