It really boils down to understanding garbage collection: memory that cannot be reached anymore is freed. In the first code sample, when running (last r), the compiler has detected that r is never used afterwards, so it clears the local variable. This means that while last is walking through the sequence one element at a time, the JVM can detect that all of the elements it has seen so far cannot be accessed anymore (Clojure seqs do not generally have any "back" pointer), so the GC is free to delete them. On the other hand, in the second code sample, when the call to (last r) is running, Clojure needs to keep a reference to r around so that it can later on call (first r), which prevents any garbage collection from happening, as r points to the first element, which points to the second, etc. up until wherever (last r) has gone so far. So you need to realize the full seq in memory.
Now to answer your question: lazy seqs are a functional programming tool. Mixing them with side effecting code is dangerous. How is that relevant? Well, your question only makes sense if you assume that your function x is side-effecting; if it isn’t the answer is simply to not call it at all and call y directly, as you wouldn’t be doing anything with the result of x anyway.
As long as you have a clear idea of the order of evaluation, you should be fine.