This is my first post, so sorry if I'm asking something someone else has already asked about. I've Googled this question over and over, but nothing relevant seems to come up.

People say that in Lisp, you should write in a mostly functional style. But they also say that you should avoid unnecessary consing. But to write in a functional style, you have to avoid modifying state and return brand new objects instead. Google's Common Lisp style guide, for example, says you should avoid giving CLOS objects setter methods, and construct brand new objects instead. So how do you reconcile these rules when you're dealing with structs or CLOS objects--do you go with the don't-modify-state rule, or the don't-cons-unnecessarily rule? Or if you switch between both, what criteria do you go by to determine which? Or am I missing the point entirely?

Style purists have little place in CL. CL is often touted as an "any paradigm" language. Some other languages are more "helpful" for writing purely functional code.

You mostly avoid consing in performance-critical code. You mostly avoid mutation in multi-threaded code. Both areas are somewhat advanced topics. "Object pools" are a cons-avoiding technique that intentionally mutates objects...

Just write code that works first. Get a feel for how the language holds together. Try various styles. Most importantly, solve real-world problems.

Google's language style guides should be taken with a large grain of salt. Last looked a few years ago, but I have seen them denounce very important techniques, apparently oblivious as to their proper use. When I've talked to their engineers, the attitude was usually "scales for big oh, slap things together fast, servers are cheap, dev time is expensive". This leads to techniques that are considered to be sloppy in the embedded systems that I usually work with.

The thing is, you say to solve real-world problems, but that's kind of begging the question, because before I can solve real-world problems I have to know how to solve them. I could solve them in a purely functional way, or I could solve them in an imperative way, or in an object-oriented way, or a data-driven way, etc. Heck, if I wanted to, I'm sure I could implement monads like Haskell and do functional programming that way. (<-- As you can probably tell, I'm the type that reads a lot of books but can't make up my mind when it comes to actually doing something.)

I guess if I had to boil the question down to one concrete, practical case, it would be: If you saw code that looked like this, say in a text adventure game:

OK, after implementing monads in Lisp just for the heck of it and seeing how wasteful of space it is, I think I'll assume my example was an inappropriate use of the functional paradigm. The time difference wasn't ridiculous, but the space difference was already big enough for a short, simple test that I can't imagine using monads on any significant scale. So by extension, given that monads are the usual way of avoiding side effects in pure functional languages, it seems like pure functional programming probably wouldn't work too well in Lisp.

Thanks again for replying, nuntius, and sorry for wasting everyone's time with a noob question.

(If anyone's curious, in Clozure on Ubuntu, with the state monad and the "do" construct implemented as in Haskell (except for using multiple return values instead of tuples, and using functions directly rather than wrapping them in other objects), for a simple sequence of pushes and pops on a list plus one call to princ, the monadic version allocated 656 bytes where the "destructive" version used 144 bytes. Which is still fairly insignificant, but as the number of operations grows you can imagine how much more memory that would take. The time difference wasn't that big, 34 microseconds for the monadic version and 26 microseconds for the destructive version. Actually, just chaining together monadic operations was much faster than and equally as space efficient as the destructive operations (7 microseconds and 144 bytes); it was running the operations after chaining that was really inefficient.)

We all have learned Common Lisp at some time in our lives, and those who are afraid to ask questions will probably never learn anything at all.

One of the points in using Common Lisp is that you do not need to worry about the programming style because you can freely mix them all together in one and the same program. Common Lisp does not restrict you to use one style only. You can for example write several versions of the same program using or mixing different programming styles, compare the results, and the choose what works best. Not many other programming languages let you do that to the extent Common Lisp does.

It's hard to tell what style to use, because that mainly depends on the problem you want to solve. Therefore it's important to write real-world programs and not care too much about books or tutorials that try to tell things like "always use this style" because that's just simply not true for all problems.

On the other hand, if you want other people to read your code there are some conventions how to indent Lisp code, described for example here: