PurelyFunctional.tv Newsletter 326: Tip: consult the repl
Sign up for weekly Clojure tips, software design, and a Clojure coding challenge.
Clojure Tip 💡
consult your repl
I've often been surprised by beginners in Slack or on IRC who ask
questions about the behavior of code. They will say "what happens when
I divide by zero, like
(/ 1 0)?"
They are asking people to tell them what their repl will do. Why not just ask the repl?
This phenomenon was so common that some intrepid hackers added a bot to IRC that would evaluate Clojure forms right in the chat. That way, they could answer the question for the beginner by asking the bot.
I've seen similar behavior with some of the people I have taught Clojure. I now believe that a big differentiator between a beginner lisper and an intermediate lisper is that the intermediate lisper uses the repl to answer questions.
This may come from a habit of using other languages. In many languages, it is not worth the effort to write a program, with a main function, set up the project, compile it, and run it, just to answer one measly little question. But in Clojure, you probably have a repl open already, so the friction is removed.
So here's the tip: the next time you want to know how something works, try to devise a small experiment at the repl. It could be as simple as evaluating one expression:
user=> (/ 1 0) ;;; try it yourself :)
Or more sophisticated, such as to answer the question "is map lazy?"
user=> (def l (map println (range 100))) #'user/l user=> (take 3 l) ;;; ???? try it yourself to see what happens
Expert clojurists don't have all the answers. But they do know how to ask questions to the repl.
a note after last-week's issue
My tip from last week (don't use protocols for testing) spurred some debate on r/Clojure.
Newsletter Maintenance 🔧
Folks, I migrated the email service I use for this newsletter. You're now reading this on the new service.
Email migrations can be tricky. I would really appreciate it if you report any issues with deliverability. That includes not receiving the email, the email showing up in spam, and any warning messages you get in your email client. I want to make sure you can get the emails you want.
The most obvious benefit to you of the new system is that I am no longer tracking links you click on. Unlike my old system, my new system can turn off link tracking. You actually know where the link will send you before you click. And nobody is tracking the clicks.
I also believe the new system has better deliverability, meaning you're more likely to get it. I am still tracking email opens, because I would like to make sure that people are getting the email. Open tracking is the best way to assess the health of your email delivery system.
Currently Recording 🎥
I am currently recording a course called Repl-Driven Development in Clojure. There is one new lesson ready this week.
- Running a Clojure repl in a Java application shows 2 different ways to run a repl in a Java application. We spend a little extra time getting nRepl to work well with Cider.
I've been getting lots of great advice from people watching it. Thanks! This is going to be a much better course because of it. If you watch it, please let me know how it can improve.
There are already 7.75 hours of video. The recording is starting to wind down. I've got a couple more lessons I'd like to record. If there is something in there you would like that you don't see, now is your chance to ask for it. It will be launching soon.
Of course, members of PurelyFunctional.tv 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.
Clojure Media 🍿
Dutch Clojure Days 2019 published its videos a couple of weeks ago. You can see them here on YouTube.
Brain skill 😎
Get active. Physical activity is known to increase oxygen flow, regulate blood sugar, and stimulate neurogenesis (new brain cell growth).
Clojure Puzzle 🤔
Last week's puzzle
The puzzle in Issue 325 was to implement Conway's Game of Life.
You can see the submissions here.
There are many ways to implement Game of Life, and I think they're all instructive.
My favorite implementation is from Christophe Grand. It's just so small. It shows that you can turn the problem inside out from how it is normally solved. All you have to do it peer hard into the heart of the problem.
When you stare at the soul of Conway's Game of Life, you can see that it's all about counting live neighbors. All of the rules hinge on that. You can also use the property that neighborness is symmetric. That is, if you are my neighbor, I am your neighbor.
Once you see that, the solution is so small. Here is my version of Christophe Grand's:
(defn neighbors [[x y]] (for [dx [-1 0 1] dy [-1 0 1] :when (not (= 0 dx dy))] [(+ x dx) (+ y dy)])) (defn step [lives] (set (for [[pos live-neighbors] (frequencies (mapcat neighbors lives)) :when (or (= 3 live-neighbors) (and (contains? lives pos) (= 2 live-neighbors)))] pos)))
This week's puzzle
Largest integer from concatenation
If I have a list of integers, I can concatenate their base-10 strings to get one large integer. However, if I reorder them, then concatenate them, I could get a larger integer. The task here is to find the largest integer you can create by concatenating a given set of integers.
Here are some test cases:
(maxcat [1 2 3 4 5 6 7 8 9]) ;=> 987654321 (maxcat [12 34 56 199]) ;=> 563419912
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.