Enigma questions from "ANSI Common Lisp"
I'm also huge fan of recursion, and the best book on recursion I know is "Little Schemer". I highly recommend it! It looks "slow" and repetitive, but that's how you learn (at least this approach was great for me).

In my opinion it's hard to read code when you find pattern you didn't knew before. It takes a lot of time and is highly frustrating to figure out what's happening inside, and often you still don't fully get why it was written this way (and if it's even correct). So the best advise I can give is - learn how to write code, reading will come naturally. You know what you are looking for.

In recursion, most important part is - when to stop and what to do (return) in that case.

Your mystery function stops when:


y is nil (it returns nil) - first if
or
first element of y is eql to x (it returns 0) - second if


It will also return logical "something and something" - the last line - but we will talk about it later.

From the above, we know that:


y should be some list, since it's user with car and cdr functions, and tested for empty list (null y)
x should be some atom, simple one, since it's compared to every element of y list with eql, which works fine with things like symbols and numbers, but not more complicated things like strings or lists


OK, we know what to pass to mystery functions (roughly). Now - what this last part with let and and do? Apparently let is used here to store result of recursive call only to speed thing up. It could also be written as:

(and (mystery x (cdr y))
     (1+ (mystery x (cdr y))))


We know what mystery function can return: nil or 0. Last thing to do is to analyse what and can return:


first argument if it evaluates to false
second argument otherwise.


As you can see there is no magical trick to help reading code. When you use some pattern (recursion in this case) long enough, you learn what are the important things to look for, and what are just common construction parts.

When you have some idea how function works, you can call it with some parameters just to verify your understanding, but I don't think you should begin with that. Pan and paper method can be a lot better, especially when you start with simple cases, like what will happen if I pass an empty list and empty list? Or zero and one element list? Calling function you don't know and observing results is called "black box testing" and is more hackerish activity. You have all the information you need - code of the function - so it's easier to read and reason about its behaviour.

When you stuck and don't know how to proceed, try to reformat the code. Rewrite the parts you understand. It might look silly and like wasting your time, but I find it helpfull.

If something is not clear, I'm happy to expand my answer, just post a comment :)