beginners 2025-09-01

Does anyone have some hotkeys, or IDE tips for beginners (in Clojure)? I feel I type println way to many times (while learning), isn't there a 'sout' equivalent? I use mainly IntelliJ.

also try to utilize the REPL as much as possible. Read about the idea here: https://blog.michielborkent.nl/inline-def-debugging.html after you realize how defs work I suggest looking into https://github.com/AbhinavOmprakash/snitch This allows you to add a * to a defn like defn* then call it and all the variables will be stored in the function. You can go then expression by expression and see what each of them evaluates to. As bonus step (not sure how it works in Intellij) you could create keymaps which execute a sequence of actions like: 1. Go to top of the file, import defn* and evaluate it 2. Go back to the function you were at, modify it to be a defn* instead a defn , evaluate it 3. Call the function with some arguments to ‘store’ the variables

You can hook taps out to sinks like #portal, #clerk, or #flow-storm (which is also a dope time travelling debugger)

I'd suggest using (tap> ...) instead and something like Portal along with it.

prn is similar to println, or even better for some purposes, while being even shorter than "sout"

That one really depends on what editor you're using, but "send form under cursor to the REPL for evaluation" is really the killer shortcut you need.

I don't know what it is under IntelliJ (Vim user), but I'm sure it exists. Maybe ask in #cursive?

You can also use: https://github.com/tonsky/clojure-plus?tab=readme-ov-file#clojurehashp Then it just becomes #p and you can inline it since it'll return the value

👍 1

Thank you guys, I'm looking up each link right now. I'm happy there's so many alternatives.

👋 Hi everyone. Clojure newbie here, recently embarked on my first real project. It's been mostly a nice ride up to now, with a lot of reading and searching. However, I am facing a conundrum I am not finding my way around with just searching and reading. And that's related to ... 🥁 project organization! Who would have thought? Jokes aside, let me describe what I got. My app is a simple cli tool to convert from one file format to another file format. The input is JSON, the output is plaintext, if that matters somehow. The way I envisioned my testing strategy is, aside from the various unit (with functions being my units) tests, which are covered enough to make me content, I also have some end to end tests, for which I use some pre-computed input/output files. That is, feed the app a JSON file and compare the output to a well known output file. The question is: "Where do I store these files? Is there some best practice already?" For now I have them under resources/, which works, but feels wrong, e.g. by sheer virtue of those test related files ending up in the jar file.

Alternatively, if the goal is to have an end-to-end test, you can also build your program then test it "externally" as a running executable using something like https://bitheap.org/cram/ or https://github.com/prysk/prysk or https://github.com/bats-core/bats-core.

1
1

A fairly common practice in the JVM ecosystem more generally is a resources folder under the test directory or a test-resources directory (depending on the rest of the project structure). In clojure specifically, that separate resources folder can be added to the classpath only for running tests via an alias/profile, much like the tests themselves.

I'd say the most common way is a top-level test-resources folder. But like @highpressurecarsalesm said, you can kind of do whatever you want. I'd say just, you don't want it to be something that'll get included in the prod build. So I'd avoid putting it under src or resources

Are you using leiningen or tools.deps?

tools.deps. I 've started my app using https://github.com/seancorfield/deps-new and it has been pretty great. I 've tried the test-resources approach and after some minor reading of build.clj and changes to deps.edn, it worked like a charm! Problem solved, thanks to both of you!

👍 1

One more thing. That's for resources that you then access as a resource. But in tests you can also just slurp files from the filesystem relative to the working directory. So some people create a testdata folder or wtv name makes sense to them under the test directory and just slurp them, no resources involved.

1

Our company offers a Clojure training. I did it. I want to share one example from this training. 🙂

(defn petToHumanAge
  "This function returns the age of a pet in human years"
  [x]
  (def petStore {'dog 7, 'cat 5, 'goldfish 10})
  (get petStore x))

(defn age
  "This function returns the age of a pet"
  [petName petType petAge]
  (def ratio (petToHumanAge petType))
  (println petName "is" (* ratio petAge) "years old in human years"))

(age "Fido" 'dog 4)
(age "Fifi" 'cat 2)
(age "Bubbles" 'goldfish 10)
I don't know if I should cry or laugh.

😱 6

"offers" : the company thinks it's a good idea to educate their programmers to Clojure. Great news! Another great news is that there is some room for improvement... Sorry to hijack the thread, but do you think there is a market for a training offer (targeting motivated developers). Training in a sense of the good old 2 to 3 days of sessions with real persons in front of a real "teacher". In Europe. Thanks for your inputs/questions

@st I feel the developers that want to do Clojure love all things computers and software, you can just observe that by scrolling through this slack. This means they're not looking into learning Clojure because there are jobs, or for financial reasons (at least not yet). In fact, just for fun, I typed "Clojure" in LinkedIn for jobs around me (in Europe) and I found 0 offerings. So I don't know who would pay for this level of training. Maybe I would, but I'm not sure if that's enough to start a business around it. What do you think?

👍 1

Not sure how useful this knowledge is, but some bits of the market are hidden. Colin, the maker of Cursive, has mentioned as much during some talk. Something along the lines of "some companies buy bulk licenses for Cursive with a stipulation that that fact will not be disclosed to the public". Unless it appeared to me in a dream. Apple used to have some job listings a few years ago that said something with the general meaning of "Clojure is required. You'll be working with all our backend services - store, iTunes, cloud, auth, etc." Suggesting Clojure is used everywhere on their backend, at least in some sense. Later job listings would say stuff like "experience with Clojure is a plus" or "experience with FP is a plus".

👍 1
💯 1
🤩 1

I might start a thread in a more suitable channel. thoughts?

Sure, why not.

@st definitely ✌️ 👍

looking for the best channel to ask the question

@p-himik thank you for this info super interesting and it does make me happier 😅

@st Maybe #jobs-discuss or #off-topic. Could even be #spam-reports.

👌 1
Alex Miller (Clojure team) 2025-09-02T15:23:32.579809Z

Cognitect used to do this style of training and at the time and it was a nice occasional business. There is a probably far outdated list of other companies or folks doing this at https://clojure.org/community/training

Thanks @alexmiller et everyone in the conversation. Will first revisit this page, before asking already answered questions.

This is better: (ns pet-age) (def ratios {'dog 7, 'cat 5, 'goldfish 10}) (defn ratio [pet-type] (get ratios pet-type)) (defn pet-to-human [pet-type pet-age] (* (ratio pet-type) pet-age)) (defn age-message [pet-name pet-type pet-age] (let [human-age (pet-to-human pet-type pet-age)] (str pet-name " is " human-age " years in human years."))) (println (age-message "Fido" 'dog 4)) (println (age-message "Fifi" 'cat 2)) (println (age-message "Bubbles" 'goldfish 10)) Would you do it differently?

@eliwal yes. Quick answer below. Specialists in this channel would probably propose something with protocols...

;; first thing first
;; I'd suggest to write unit tests
;; and separate data from display.

(def ratios
  {:dog      7
   :cat      5
   :goldfish 10})

(defn ->human
  [pet-type pet-age]
  (* (ratios pet-type) pet-age))

(defn message
  [pet-name pet-type pet-age]
  (str pet-name " is " (->human pet-type pet-age) " years in human years."))

(comment
  (println (message "Fido" :dog 4))
  (println (message "Fifi" :cat 2))
  (println (message "Bubbles" :goldfish 10))
  )

better, uses keywords and the map as a function

No, protocols would be total overkill here. KISS.

➕ 1
👌 1

> Specialists in this channel would probably propose something with protocols On the contrary, there's no dynamic dispatch needed anywhere with such a trivial problem.

➕ 1
👌 1

@st I agree! Keywords are better because they can be used as functions. The name ->human, that's subjective if it's better but at least it's shorter. Commenting out the println, well if you are going to run the program then you can't do that...

(comment ...) is not really "commenting out". It's called a "rich comment form" and is usually used in a REPL - precisely so you can experiment while keeping the process of loading a namespace free of side-effects. If printing should be done as a part of running the program, and that program is not a trivial script, it should be put in the body of the -main function, or some other function that ultimately gets called by -main.

@p-himik I know. But this is a trivial script.

In the context of the thread - maybe. We don't see how it's being run. Well, at least I don't know how it's being run in that course. And we're in #beginners. ;)

😂 1

By the way, if using the REPL it's better to just: (comment (message "Fido" :dog 4) (message "Fifi" :cat 2) (message "Bubbles" :goldfish 10))

👍 2

@eliwal I'd probably change a few things from the original: • Model a pet explicitly • Avoid functions accessing a global variable • Separate pure behavior from impure one (like printing) • Use keywords instead of symbols • Use Clojure kebab-casing

(ns my-app.pet)

(defn make-pet
  [name type age]
  (let [human-age-ratios {:dog 7 :cat 5 :goldfish 10}]
    {:name name
     :type type
     :age age
     :human-age-ratio (human-age-ratios type)}))

(defn human-age
  [pet]
  (* (-> pet :age)
     (-> pet :human-age-ratio)))

(defn human-years-message
  [pet]
  (format "%s is %d years old in human years."
          (-> pet :name)
          (-> pet (human-age))))

#_
(do
  (-> (make-pet "Fido" :dog 4) (human-years-message) (println))
  (-> (make-pet "Fifi" :cat 2) (human-years-message) (println))
  (-> (make-pet "Bubbles" :goldfish 10) (human-years-message) (println)))

Or if we wanted to keep it super dumb/simple I'd just do:

(defn print-pet-human-years
  [pet-name pet-type pet-age]
  (let [human-age-ratios {:dog 7 :cat 5 :goldfish 10}]
    (println
     (format "%s is %d years old in human years."
             pet-name
             (* pet-age (human-age-ratios pet-type))))))

#_
(do
  (print-pet-human-years "Fido" :dog 4)
  (print-pet-human-years "Fifi" :cat 2)
  (print-pet-human-years "Bubbles" :goldfish 10))

Does this training happen to be available online? Would be really interesting to see how companies are driving new clojurers to prepare them for the market.

I just noticed this is part of the Udemy course I'm doing I've done this challenge already 😅 👍 ✌️

The code sample was from a "what not to do" section, right? Right?..

😂 3

How not to do OO in Clojure. 😜

it's way before you start with Fundamentals

at this point you only know what an hashmap is

not even ifs/conds etc...

It is after having learnt the fundamentals. Then there is a home work for the audience. And that code is the example solution for the home work.

🤡 1

for me is before fundamentals

ill take a screenshot in a few

Maybe you should overhaul the examples.

Screenshit is good. 😂

damn u caught my typo 😂

Never mind, I'm prone to typos, too

😅 1
Alex Miller (Clojure team) 2025-09-01T20:23:43.187369Z

That udemy course is quite bad

I feel you, but beggars can't be choosers 😅

I'd usually agree with that sentiment, but do you really want to learn the language from someone who can't even get basic idioms right, like camel vs kebab case and nested defs? Are you really learning at that point?

☝️ 1

Jason how did you learn Clojure?

I personally learned a lot from books, paper books even. "The Joy of Clojure", "Progamming Clojure", "Clojure Programming", "Clojure Applied" and a few more.

I tend to buy every Clojure Book I get my hands on.

🎉 1

I'm doing my best with the resources I have found. I have some very solid understanding of multiple programming languages and paradigms so I'm just looking at the course to know the syntax and then will eventually do what I usually do which is to learn by building something with a real applicable use case. I initially started with a guide by Pavel Klavíc who I see as well reputable Clj Dev and then checked the Udemy course.

Thank you so much @lsolbach I will search for those immediately.

Have you tried the official reference docs at the Clojure website?

Yes I have them on my 2nd monitor constantly open :)

But I usually start with a small crash course just to get the Fundamentals down fast.

Fast and wrong tends to be slower than slow and right. :) The "Learn Clojure" section of the official guides is not that large, but it covers all the essentials.

I started with The Joy of Clojure, but it really wrinkled my brain. I read through Clojure for the Brave and True (not everyone's style, for sure, but I found it more beginner friendly than Joy) and then came back to Joy (and also read all the books Ludger mentioned). I worked through several Advent of Code puzzles, and I listened to the entire Functional Design podcast and watched several videos of experienced Clojure programmers doing their thing (Arne of lambda island, the Parens of the Dead video series, a video or two of Sean showing his workflow). It was a slow burn, for sure, but I felt like I absorbed quite a bit by thinking through coding problems and hearing/seeing people who know the tools work through problems. It eventually re-wired my brain (especially the podcast)

@p-himik I totally agree with you.

@jason.bullers thank you so much for this feedback, I will for sure apply this right now. I'm at the point where I can write some basic Clojure scripts and I feel I understand the "flow" of the language.

I'm not in a rush, I for sure I'm looking to where I want to be in a few months or even a year or two's time - and it is to be programming daily in Clojure.

Lots of gold in the resources y'all are sharing. Thank you so much you won't imagine how appreciated I feel. ^_^

👍🏻 1

@jason.bullers I went on Amazon and wrote "The Joy and Clojure" and without any input of mine Amazon made the "frequently bought together" of both.

This is a bit expensive for a poor dev in the trenches like me though. I might look into digital copies if there's any.

You're better off having ChatGPT teach it you 😅

Dunno about the joy of clojure pdf, but the clojure for the brave and true book is available for free on http://braveclojure.com

What is even this function haha. I mean, that's not even just bad Clojure, it's just bad coding.

That liango2/clojure-ebook repo seems... unwise... since it is PDFs of copyrighted material and based on the commits, it looks like at least some books have been removed, likely at the request of the publishers who this is undercutting.

When I was learning, I remember really liking this: https://aphyr.com/tags/clojure-from-the-ground-up And also being surprised how good reading the official reference: https://clojure.org/reference/reader I tried Clojure for the Brave and True and didn't like it, it never helped me learn it I feel. Then I went through all of 4Clojure: https://4clojure.oxal.org/ And then I started coding things with it and figuring/researching only what I needed to make progress.

https://www.clojure.org/guides/learn/clojure and https://clojure-doc.org/articles/tutorials/getting_started/ are good places to start a legal and useful learning journey with decent code.

And you really really need to be inside the REPL typing at your editor and sending forms (not typing at the repl) 24/7

I removed the link as I don't want to promote anything wrong. Thank you for pointing it out @seancorfield 🙏

👍 1
👍🏻 1

Guys I'm making a huge bookmark list of all your resources 😂 I love nerding this stuff out so I'm in for a treat. Bless you ✌️

1
🤘 1

Clojure is so cool, it's really where I want to be in the future. You can tell immediately through this community and so far from my experience it's where I want to be. I've come from C, C++ then at my job Java 8, Groovy, Bash, Python I have learned Rust and even a bit of Haskell in my spare time, but oh man Clojure is that something I wish I had learned earlier. 😐

❤️ 9

Hawkwind, the band? I love them!

It's rare to find anyone who has heard of them! They were the second band I ever saw live, back in 1978. Saw them multiple times. At one gig I was pressed up against the stage and Nik Turner was hopping along the front of the stage on one leg playing his saxophone and kicked me in the head with his other foot -- my "celebrity encounter" claim-to-fame 😄

I discovered them relatively late, maybe in the late '90. In my opinion, they made real classics, not just Silver Machine. I love Right to Decide and Alien I Am, for example.

One of my all time favorite bands is Alien Sex Fiend, but it's really rare to find anyone, who has heard of them, especially outside of the UK. One concert I of them was the best I've ever seen. At a small location in the main train station at Dortmund with an audience of maybe 200-300 people. If I need a hearing aid in the future, that will be the reason why. 😅.

ASF were great -- but then I'm from the UK (sorry to everyone in this thread that it's becoming an "old fogies' music reminiscence" thread -- we should probably move to #music at this point)

😅 1

Didn't even knew #music exists

You're in the Clojure community the ppl here have great taste and culture 😁

Thank you for this motivating message right after my super frustrating message 3 minutes earlier!

Even I wished I had learned it earlier and I learned it in 2011. 😅

My PL arc mostly follows yours -- C, C++, Java, Groovy -- all for work, with Python, Rust, and Haskell in my spare time. And I have never enjoyed programming as much as the last 15 years doing Clojure! 🙂

> And I have never enjoyed programming as much as the last 15 years doing Clojure! 🙂 Wow 15 years of Clojure, and for you to say "never enjoyed programming as much", this really hit me hard. I can already feel it and I'm just giving the first few baby steps. I think Clojure really amplifies creative people who love to build stuff.

I've been programming professionally for about 45 years now -- and another 5 before that as a hobby 🙂

Sean, I think, you're old. 😅

I just turned 63 in July so... yeah... I think I'm old too! 🙂

I started programming in school 44 years ago. 😅

VC20 Basic that was

My first programming was the Sinclair Programmable Calculator in the mid-'70s. Then my school did an optional correspondence course with the local technical college so we could learn Algol-60! 🙂 And there was a lot of BASIC and assembler in those early days too...

After that Z80 Assembler, Pascal, C, Perl, Java, AspectJ and finally Clojure.

Heh, I try to forget the Perl I did in the early 2000s when I worked at Macromedia 🙂

🙈 I've worked in hardware (eletronics) for 7 years and only been professionally in SWE for the last 3 years. I feel so humbled right now. You guys feel like pools of knowledge. I worked with someone like you who's like the only person who writes perl and some other old languages, he's in his 60's and one or the ppl I admire the most.

My first computer was a ZX Spectrum and I still have a Sinclair QL and an Amiga 3000 in the basement.

I did my master thesis in Perl. 😅

One day he was sharing some stuff he did for a project we were both involved in, and he just opens some terminals to show his code like just editing his code in something resembling vi but no syntax highlighting just white letters on a terminal.

That day I knew I was universes out of his league 🙈

rikkarth, you are young and can still accumulate all the knowledge. And some of those languages are not that good, IMHO.

❤️ 1

The options for tooling and editing are so, so much better these days than back when "I were a lad"...

👀 1

And today you can let the AI help you. That's a bit like pair programming.

Sean, punch cards?

I did punch tape, not cards. That's how we backed up our code at university. I did do the whole "coding sheet" thing where you wrote out your code and operators typed it in for you and ran it, and sent you a big printout a day or two later.

👀 1

I'm from the 90's so I have no clue how that feels like, but it must feel how I feel about VHS and "not having internet" with the new generation now.

We had access to pre-Internet at university - we were part of JANET, and we used it to log into various remote systems. I got dialup in the early '90s (Demon Internet in the UK), so I had email, chat (irc), forums (Usenet). I had my own domain and website by the mid-'90s. I met my wife online back then, on Usenet, although we didn't start dating until '99 (when I moved to America).

Anyone still remembers Gopher?

Oh yes!

what an awesome story @seancorfield

the internet of back then was really about connecting real people

Web before the Web. 😅

Back in the mid-'90s, you tended to actually know everyone you encountered online - can you imagine that? Not in real life but as actual people rather than just nameless people behind a username.

I was really active on IRC and a bit on Usenet. Mostly on Amiga channels and groups. Build a route planner for the Amiga as shareware starting '93 and created a free web version with Perl and FastCGI in '96.

That had dynamic map generation with GD.

We had programmer meetings in Germany, where you would meet your buddies from Usenet and IRC. They were held at universities mostly and took place 2-3 times a year. They were great fun and you could learn a lot there.

I had a System 6 Mac, with Tenon Intersystems MachTen BSD 4.3 Unix installed as an "application" -- Mac UI, Unix command-line -- in the early '90s. Cost 500 quid for that package, as I recall. But it let me write a mailing list server in C, and I ran the Peter Hammill and Hawkwind mailing lists on that, via dial-up Internet for several years. A penny a minute, off-peak rate, so I dialed in just after 7 pm every night and left it online until just before 7 am every morning, and then at weekends from 7 pm Friday to 7 am Monday. I was terminally online even back in the early '90s!

Hi!! I'm confused... I have a function that takes a vector of maps. Some maps have a key :question and I want to create a new vector using only those maps. Using (println) I can see that I'm sorting out the the correct maps, but I'm not getting the final result, a vector with those maps. Is it a scope issue?? (recur) is outside of the (if) expression. If it is inside the loop stops. Also, is this even how one should approach this? It seems a little verbose.

(defn list-questions
  "Creates a new vector of maps from another vector of maps based on keyword."
  []
  (loop [ex exercises
         newvec []]
    (when (not-empty ex)
      (let [[hd & remaining] ex]
        (if (contains? hd :question)
          (do
            (println hd)
            (conj newvec hd)))
        (recur remaining newvec)))))

It's often better to think of pipelines. First you have the vector of maps. Push it though some function. Then push the result of that through another function. Extend the pipeline until you have the desired result. (->> excercises (filter :question)) or if you want only the questions: (->> excercises (filter :question) (map :question)) or same result: (->> excercises (map :question) (remove nil?))

I think it'd be a great exercise to try and make your original (posted) attempt work. The filterv solution is the idiomatic one, and the one you should use in "real" programs, but I think getting your original loop-based attempt to work may help a few key concepts "click".

@eliwal I can see that. I feel like I've also heard people talk about functions being composable. Is that the same thing? Thank you.

@gaverhae I was just thinking this last night. Whether the loop is appropriate here or not, not getting it to work feels like kicking the can down the road a bit. Thanks for the nudge.

Aha! I got it. That took an embarrassingly long time. I believe I was stuck on a top down (imperative?) approach. Here's to another step towards thinking outside the box and inside the parens. Thanks again to everyone for the comments, suggestions, and encouragement.

(defn list-questions
  "Creates a new vector of maps from another vector of maps based on keyword."
  [exercises]
  (loop [ex exercises
         newvec []]
    (if (empty? ex)
      newvec
      (let [[hd & remaining] ex]
        (recur remaining (if (contains? hd :question)
                           (into newvec [hd]) newvec))))))

You could use (->> exercises (filter :question) (into []) to do the same.

As Elias pointed out, thinking in data pipelines makes things a lot simpler.

Cool! Thank you. Yes, I figured there's probably a few ways to achieve this. Most of which are better than mine. I really wanted to get that (loop) working even if it isn't an idiomatic or even good approach. I really want to spend more time with clojure.core so I have these functions at my finger tips.

Congratulations! Minor nitpick: from a performance perspective, (into newvec [hd]) unnecessarily creates a one-element vector then iterates over it. You could just add the element using conj instead; conj adds at the end on a vector.

One more hint: any keyword is a function too. Investigate what happens when you apply :question to a map.

Yes, I actually use (:question some-map-name) to retrieve the data associated with the key. I'd say it's convenient, but it's more than that. Clojure is the first time I've ever thought code was elegant. No shade to other languages, but I'm a hobbyist, so I have limited experience with this kind of thing.

(filterv :question vec) will work, as long as you don't care about the value of :question being nil or false (those would be treated the same as :question not being present). Per genmeblog's hint above.

(filterv) worked great but still need to throw some different scenarios at it. I'm still at probably less than 20 hours with Clojure and right now it's all for fun so I'm not terribly concerned about things breaking. As long as I keep learning.

Something I think is worth mentioning in your original code is that Clojure data structures are immutable. This means that when you conj to newvec in the if, you have to capture the result, otherwise it's lost. Clojure doesn't let you conj "in place", so the recur will always see the empty newvec (in other words, what you're printing out is what you're visiting, but not what you're capturing)

Thank you, I caught that in a previous iteration too. One thing I've learned in the past few days is that I know Clojure is immutable, but I don't always see how I'm attempting to use mutability in my code.

I tripped over the same thing when I started. It wasn't always clear how to move away from "loop and bash in place"

That's really good to hear, thank you. I've had to remind myself more than once that there's quite the learning curve.

A guiding principle that I've tried to adopt that helps remind me of that: consider loop to be a last resort -- I use it only when it would be harder to read/reason about "simpler" solutions using sequence fns or transducers. loop isn't like the loop construct found in other languages, so I always try to reach for something else first.

➕ 1

Ahhh, good to know, thanks.

@ryan507 The threading macro (`->>` or ->) is a practical way of composing, but the comp function is the more basic or mathematical way: ((comp #(remove nil? %) #(map :question %)) exercises) or ((comp (partial remove nil?) (partial map :question)) exercises) As you can see, it's much simpler to use threading in this situation, and more intuitive since the order of doing things is from left to right. Sometimes comp is useful though.

Cool, thank you both. I will keep both of these in mind. I’m glad I posted this. It seemed to be a trivial problem, but served as a conversation starter and I learned a lot.

👍 1

in short, the result of the loop is the result of the when, so when the when condition is true, then recur happens, and when it's no longer true, then nil is returned (the 'else' on the when)

You need an if with an else branch that actually returns the value

Here are some questions about your code that might help you investigate what's happening: • what happens if ex is empty? • what happens if ex only contains one map with a question? • what happens if ex is a vector of two maps with a question? • what happens if ex is a vector with one map that has a question, followed by a second map without a question?

Great, thank you, all! My brain was about to explode. I will keep working with the information and questions here. Much appreciated!!

one suggestion that might help you investigate your code is to make exercises an argument to your function, so you can try calling it with different values in the repl to see what happens.

That's a good idea too. Thank you. I'll report back tomorrow when I have more time to dig in.

Also look at filter (or filterv to return a vector) since that is what you are doing here.

➕ 2

Thank you! This felt like it would be a common task, but nothing jumped out at me in the API docs.

@seancorfield that did it! Thank you. I had a feeling my earlier attempt was too verbose.

(defn filter-for-questions
  [vec]
  (filterv #(contains? % :question) vec))