PurelyFunctional.tv Newsletter 321: Tip: Do not count sequences from strangers

Sign up for weekly Clojure tips, software design, and a Clojure coding challenge.

Issue 321 - April 8, 2019 ยท Archives ยท Subscribe

Clojure Tip ๐Ÿ’ก

do not count sequences from strangers

If you are writing a function that operates on sequences, be really careful what you do with it. Clojure's sequences are lazy, and that can be really powerful. So powerful, in fact, that the sequence could be infinite โšก๏ธ. A stranger could hand you a sequence. It could have three elements. Or it could be an infinite sequence. There's no way to know.

And how long does it take to count up an infinite sequence? Don't hold your breath. You will die. In fact, even if you keep breathing normally, you will die before you reach the end. I don't want you to die. So don't call count on sequences from strangers.

I made a lesson about this called Gotcha: length checks. Not a great name, but a good lesson to learn about checking the length of a sequence of unknown origin. Don't do it!

Well, there is a way to do it safely. Let's say you're tempted to do this:

(< 4 (count s))

where s is your sequence. Stop! Let's think about this. You want to know if the length is greater than 4. So do this instead:

(< 4 (count (take 5 s)))

Take the first 5 elements, and count those. It's at most 5 elements long, but could be less. Or you could do this:

(seq (drop 4 s))

Is s longer than 4? Drop the first 4 elements, and see if there's at least one more (with seq).

Whatever you do, don't count a sequence directly, unless you know it won't be infinite. If you do count it, you're in for one long coffee break.

โ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธโ˜•๏ธ...

Follow-up ๐Ÿ™ƒ

a few notes after last-week's issue

In response to my shebang script, Tobias Locsei mentioned inlein, which lets you run Clojure scripts with dependencies.

If you tried to reset your password on PurelyFunctional.tv in the last couple of weeks, it was broken. But it's fixed now. Just request another link and it will work.

Currently Recording ๐ŸŽฅ

My new course called Repl-Driven Development in Clojure has 2 new lessons this week.

As you know, Repl-Driven Development is all about getting into flow. And to get flow, you need fast feedback. To get fast feedback, you need to write code, compile it, and test it really quickly.

The first lesson is about tools that you can use to write code faster. You're probably familiar with most of the tools. They include structural editing, rainbow parens, and linting.

The second lesson is all about testing quickly. How can you quickly go from compiled code to confidence that your code works (or confidence that it doesn't :)? That's what this lesson is all about.

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 4 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 ๐Ÿ˜Ž

Learn in short bursts. The brain seems to learn more at the start and end of learning sessions. Don't study or practice all day without breaks. Get up, take a walk, or take a nap. The recommendation is to study for 30-50 minutes, then take a break.

Clojure Puzzle ๐Ÿค”

Last week's puzzle

The puzzle in Issue 320 was to write a function to remove the nth element of a list. I asked for it to be robust and for people to document their choices in comments.

You can see the submissions here.

I saw a couple of approaches. One was to defer to whatever Clojure's functions do. That is, write the obvious solution for the normal case, and let Clojure's behavior dictate what happens for the non-normal case. For instance, what happens when the index is higher than the length of the sequence? Typically, Clojure ignores it.

Another approach was checking the arguments with guards and throwing exceptions. This gives you the flexibility to add checks, even if the Clojure functions underneath do not check. The challenge is to get that working with infinite sequences, as in this week's Clojure tip. You can't ask for the length of a sequence, lest it be infinite, in which case you'll learn the length at the end of the universe. Not recommended.

Exercise

Where do these submissions fail? Do they work in the normal case? Can they handle infinite sequences? What if the index is out of bounds?

Thanks for participating!

This week's puzzle

binary divisible by 5

Write a function that takes a string of binary numbers, separated by commas. It will look like this:

"1100,101,111,1111"

Take that string, parse out the numbers, and return a string, in the same format, that only includes numbers divisible by 3.

The return value for the above string would be:

"1100,1111"

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 โœ๏ธ

April Fools! I'm not going anywhere. The PS last week was a bad joke.