PurelyFunctional.tv Newsletter 320: Tip: Know Clojure's execution semantics for better Repl-Driven Development
Issue 320 - April 1, 2019 ยท Archives ยท Subscribe
Clojure Tip ๐ก
Know Clojure's execution semantics for better Repl-Driven Development (RDD)
I've been working on the Repl-Driven Development in Clojure course on PurelyFunctional.tv. When doing my research, it struck me that most explanations of RDD fail to explain how Clojure actually executes code. They take it for granted that people know it, when why should a beginner know that?
When you're doing RDD, you are controlling the execution of code down to the individual expression. You need to understand how Clojure executes code.
I have a whole lesson on it, which goes into a lot of detail. But here are some key points to take away:
- When a file is loaded by Clojure, each top-level expression is compiled and executed one at a time.
- The namespace declaration form (
ns
form) is just an expression like any other. It create a new namespace, which is an internal data structure for storing Vars. - Vars allow for dynamic redefinition of functions and global variables. They are a reference type. They hold a value, and the Clojure language will implicitly dereference them when you refer to one by name. Learn more about Vars in Daniel Solano Gomez's talk from 2014.
- Taken together, executing
def
s andns
forms create a kind of key-value database in-memory. You can access those things in your code and at the REPL.
Follow-up ๐
a few notes after last-week's issue
In response to my shebang script, Alan Thompson clued me in to lein-exec, a Leiningen plugin to run Clojure scripts.
The puzzle a couple weeks ago was about generating combinations. I haven't been very strict about correctness at edge cases, which Steve Miner has pointed out to me. But I will be now. He also mentions the clojure.math.combinatorics library, which has industrial-strength versions of common combinatorial functions.
Finally, I keep forgetting to mention that there was some downtime on PurelyFunctional.tv on March 8, due to an automated server upgrade---while I was on vacation :(. Well, I did my best to fix it on my phone as soon as I found out about it. I managed to get the site back up and mostly functional, but the site was down for at least 4 hours. I've put in place some precautions to prevent the same thing in the future. Sorry it happened, and double sorry for forgetting to mention it for so long.
Clojure Media ๐ฟ
:clojureD happened recently and many videos are online. I'm looking forward to watching these.
Currently Recording ๐ฅ
My new course called Repl-Driven Development in Clojure has 2 new lessons.
The first one is about what you should do when you're first starting an RDD coding session.
The second lesson is three demonstrations of how to interactively develop new functionality using RDD. I go over inside-out programming, setting up small tests, getting your testing data set up, and doing small experiments. If you've never seen it before, you'll see how quick the development loop can be.
The course is available as of right now as part of an early access program (read serious discount). If you buy now, you'll receive updates to the course as new lessons come out. There is already 3 hours of video, and many more coming. If I had to guess, I'd say 6-8 hours total when I'm done. But I can't be sure. That's what the discount is for. As the course is fleshed out, the price will go up.
Of course, members of PurelyFunctional.tv will get the course as part of their membership for no extra cost. Just another benefit of being a member.
Check out the course. The first lesson is free.
Brain skill ๐
For this week's brain skill, I'm just going to refer to my podcast episode where I give recommendations for finding the time to learn functional programming---or any larger skill, for that matter.
Clojure Puzzle ๐ค
Last week's puzzle
The puzzle in Issue 319 was to write a function that gave you a list of digits, given a number and a radix. Lots of great submissions.
The two main approaches seem to be:
- Convert the number to a string using the radix, then split the string into digits.
- Iteratively divide the number by the radix, using the remainder as the digit.
Both are valid and have their advantages. The string-based approach gives you digits greater than 9, for instance with a radix of 16. The division-and-remainder approach would simply give you a number greater than 9.
An intriguing exercise would be to go through the solutions and find out where they fail. Do they work for negative numbers? What if the radix is a weird number like zero or one? Do some snooping and see if you can find out where they break.
Thanks for participating!
This week's puzzle
remove the nth element from a list
Clojure's two main sequences, lists and vectors, do not easily let you
remove an item from the collection when that item is in the middle of
the sequence. Sometimes we need to do that. Write a function remove-at
that removes the element at position n
from a seque
nce.
(remove-at 3 [1 2 3 4 5 6])
; => (1 2 3 5 6)
Make this robust. You'll have to make some hard design decisions like
how to handle the empty sequence, how to handle out-of-bounds n
, and
more.
Bonus points for clarity and efficiency. But the #1 priority is completeness and correctness. Please document your choices in comments.
Extra credit: write a separate version for sequences and for vectors. The vector version should take and return vectors.
As usual, please send me your implementations. I'll share them all in next week's issue. If you send me one, but you don't want me to share it publicly, please let me know.
Rock on! Eric Normand
PS โ๏ธ
I would like to announce my retirement from Clojure. As soon as I finish Repl-Driven Development in Clojure, I will consider Clojure learning material a solved problem. We always knew there would be an end, and it has been a good run.
Three factors combined to help me make this decision. The first is the recent Clojure 1.10.1 point release. The instability of Clojure has become a real issue, and upgrades seem near constant now and each more costly than the last. With all of the churn, I might as well be doing JavaScript at this point.
The second factor is more personal, but my doctor has told me I have severe repetitive strain injuries in my hands and wrists. He asked me what editor I used and when I told him Emacs with Cider, he shook his head and recommended I give VS Code a try.
The X-ray revealed extensive cramping my left hand, which he said was called Emacs Pinky. My right index and middle fingers showed serious bruising in the tips where they hit open and close paren. My doctor estimated they were used about four times as much as my other fingers. When I mentioned that JavaScript and other C-style languages have more braces than Lisp, he scoffed in disbelief. He recommended I go full time in JavaScript to see if that won't relieve some of th e numbness in my hands.
The third factor in this decision is that the Clojure community has completely stopped growing. I always knew it was small, but just yesterday I could see almost a full week of the slack message history on the Clojurians Slack. I would expect by now to hit the 10k message limit at least daily, if not more often.
JavaScript is now the most popular language in the world, excepting
Visual Basic and Excel (which I did consider switching to). It has a
large community and very mature solutions. With only a few npm install
commands, the whole world is at my worn-down fingertips. Since the
ecosystem is stabilizing on React, it has fewer parens (according to my
doctor), and VS Code is so nice, I'm making the switch as soon as
possible.
Expect to see some JavaScript tips from me in the future, like what this means
(()=>({}))()
in future issues.