1) Like you say, the substitution operator doesn't do what you want; it's only for real variables. This is because it is an operator that needs an lvalue to modify. You can't use s/// with static strings for the same reason you can't do "'x'++;" or "'x'=3;". If you don't want to create a new variable, the fastest way is to assign your static or interpolated string to $_ and then use the substitution operator; then you can even drop the binding operator =~.
2) Sorry, you have to type the five extra characters "$_ = " :-P. The insanity resulting from putting the result of every statement into $_ would far outweigh the small convenience. You'd always have to be on the lookout for what blew away $_ (even more so than now); I suspect it would make the variable much less useful. Also, explicitly putting in the assignment makes the code significantly clearer; even if you could take it out, you probably shouldn't.
3)This is what numerical indices are for. Sorry, but you can't throw out all your C habits ;-). Just have an integer variable (say, $i) and then when you need to reference the previous value use $_[$i-1]. For (which is a synonym for foreach) does require at least one parameter; if you want an infinite loop use for(;;){...};. On another note, @_ doesn't have the same "temporary" role that $_ does. @_ is for passing arguments to subs, so once again it's much more clear and barely more difficult to just type it. On an even less related note, while loops DO have funky semantics when you use "<>" as the sole argument. Namely, it will take elements from @ARGV, assume they are filenames, get data from those files, then read from STDIN.
Update: foobah's comments below are all correct; I fixed the first but check the others for clarifications.