3 ms·
Compared to other languages, I've found Clojure makes it much easier to iteratively turn an idea into code. Say you're writing a pure function... You start wi
by mbil 6y ago
Compared to other languages, I've found Clojure makes it much easier to iteratively turn an idea into code.
Say you're writing a pure function...
You start with just data and a sense of how the output might look. Let's say I have APIs providing me with a user record and a list of transactions, and I want to get that person's balance...
Maybe you start with some canned data
(let [person {:name "Matt"
:id 12345
:current_balance 100.10}
txns [{:person_id 12345 :amt 10}
{:person_id 44444 :amt 0.5}
{:person_id 55555 :amt 10}
{:person_id 12345 :amt 11}
{:person_id 12345 :amt -5}
{:person_id 66666 :amt 3}]]
(->> txns
count)
)
=> 6
and maybe you want to filter the transactions to just that user
(let [person {:name "Matt"
:id 12345
:current_balance 100.10}
txns [{:person_id 12345 :amt 10}
{:person_id 44444 :amt 0.5}
{:person_id 55555 :amt 10}
{:person_id 12345 :amt 11}
{:person_id 12345 :amt -5}
{:person_id 66666 :amt 3}]]
(->> txns
(filter #(= (:id person)
(:person_id %)))
count)
)
=> 3
then you want to extract the amount for each of those
(let [person {:name "Matt"
:id 12345
:current_balance 100.10}
txns [{:person_id 12345 :amt 10}
{:person_id 44444 :amt 0.5}
{:person_id 55555 :amt 10}
{:person_id 12345 :amt 11}
{:person_id 12345 :amt -5}
{:person_id 66666 :amt 3}]]
(->> txns
(filter #(= (:id person)
(:person_id %)))
(map :amt))
)
=> (10 11 -5)
and sum those amounts
(let [person {:name "Matt"
:id 12345
:current_balance 100.10}
txns [{:person_id 12345 :amt 10}
{:person_id 44444 :amt 0.5}
{:person_id 55555 :amt 10}
{:person_id 12345 :amt 11}
{:person_id 12345 :amt -5}
{:person_id 66666 :amt 3}]]
(->> txns
(filter #(= (:id person)
(:person_id %)))
(map :amt)
(apply +))
)
=> 16
and add that to the existing balance
(let [person {:name "Matt"
:id 12345
:current_balance 100.10}
txns [{:person_id 12345 :amt 10}
{:person_id 44444 :amt 0.5}
{:person_id 55555 :amt 10}
{:person_id 12345 :amt 11}
{:person_id 12345 :amt -5}
{:person_id 66666 :amt 3}]
bal-change (->> txns
(filter #(= (:id person)
(:person_id %)))
(map :amt)
(apply +))]
(+ bal-change (:current_balance person))
)
=> 116.1
the function is done!
(defn update-person-balance [{:keys [id current_balance]} txns]
(let [bal-change (->> txns
(filter #(= id
(:person_id %)))
(map :amt)
(apply +))]
(+ bal-change current_balance)))
I posted here as a series of snippets, but this would have been a single block of code, refined and evaluated and refined and evaluated, over and over, in a REPL-integrated editor. It feels like sketching a portrait or sculpting clay.
"But I can do that in any ol' REPL!" you might say. Try Clojure -- really try it, with an nREPL connected to your running application and to your editor, capturing inputs, playing them back, writing evaluation output as comments -- and then tell me you want to go back to your old REPL. A notebook environment is similar, though clumsier IMO.
Come for the REPL-driven-development, stay for the immutability, the Java library ecosystem, the lisp syntax, the concurrency support, etc. I know going on and on about how great Clojure development is is basically a meme at this point, but that's because it's really great!
- fhsm 6y agoHow do I know if I’m really trying the repl/editor cycle? I mess with Clojure with some regularity and each time ultimately back away in a combination of frustration and nerd sniping self awareness as the ratio of editor setup blog reading meta work to actual work hits infinity. Either I am terrible at finding good setup guides or it’s pearls before swine and I just don’t get the aha moment. I’m starting to think it’s the latter.
- silly-silly 6y agoNah mate, Stay positive. You're not the 'swine' here, you shouldn't feel that way. I've learned that sometimes paradigms require the programmer to be in the correct 'frame of mind' before it even begins to make sense, its not you. In my limited experience, keeping an open mind to tools will get you much further and have more enjoyment in your career and life. Trying to force that square peg into the round hole will just make you hate new things. If the time comes and your mindset is right, the tech will still be there.
- Folcon 6y agoI'm in agreement with silly-silly, but I must say I spent an embarrassingly long time coding before I worked out how the REPL editor workflow worked, and nowadays I feel a bit spoiled because I really do miss it when I'm programming in another language like python. Jupyter notebooks come close, but not quite there. The thing that really helped was watching videos of talks / tutorials of people on youtube coding something up, for example [0]. I'm not calling that one out specifically as a great tutorial, that's just an example of what I mean =)... I personally would start with an example of a form and then build it up in stages, basically tinkering with the form as I work out how I want it to function. Another thing is that you don't have to use a particular editor etc. I'm not sure for example if you think you have to use emacs. Don't get me wrong it's a great environment, but if you're a beginner to it and clojure, that's not a good combination. Pick something you like which hopefully has a good repl plugin. There are a fair few options these days. Intellij, vscode, atom, vim among others. Worst case if you'd like me to sit down and have a short call to go over stuff I'd be happy to set aside a little time =)... I've done tutorial stuff before and it's always nice to help someone else get comfortable in the ecosystem. Hope that helps. - [0]: [Clojure, REPL & TDD: Feedback at Ludicrous Speed - Avishai Ish-Shalom](https://www.youtube.com/watch?v=Ngt29DyNDRM https://www.youtube.com/watch?v=Ngt29DyNDRM)