Oops, I had a $0 in a message box which just works in Purr Data.
Try this:
Paradigms useful for teaching Pd
@jancsika Ok, now it works. Only [dup i 20, i < 45, i + 1] gives just bangs. 
Have you seen my [loop], [for] and [for++] abstractions? These together with [expr] or other objects can do everything with less complexity...
My main purpose was-- can I use "i" to set a loop and reference "i" in the body of the object's arguments as a local variable? Even that turns out to be extremely difficult. And while I purposefully avoided using abstractions here, it wouldn't have changed much because the difficulty is in the core data structures available from the language.
You're right that just reading a single "$f1" in a separate expr isn't a big cost. But what about extending "i", with "j", or "amp" and "freq" and "dur"? In other languages people iterate over a design pattern to create everything up to (and sometimes beyond) a domain specific language. In Pd I can't easily add this seemingly simple convenience. The language just doesn't give me enough features to do it in a robust way. (And while I specifically avoided abstractions here, that wasn't the limiting factor.)
As far as teaching paradigms-- I think this means to stick to lists of floats even when teaching general principles like what OP covered above. If you're splitting or mapping lists of symbols or lists of symbols and floats, it's likely you'd be better off doing that business in another language and handing the results off to Pd.
As for Lua-- maybe that's the language to go to for handling these higher-level problems? The pdlua stuff looks great, but I wouldn't want to downplay the cost of adding another language to the mix, especially for newcomers.
Ok, now it works. Only [dup i 20, i < 45, i + 1] gives just bangs.
Hee hee. I actually designed it that way with [until] in mind. But yeah, it should probably just output "i" implicitly in that case.
@jancsika It is pretty cool! 
Interesting progress on this thread! I'd dropped off -- will have to catch up.
Of scripting languages -- I'll get myself in hot water for saying this, but every really cool max or pd project I've seen involves some scripting objects somewhere. There are some things that are really hard to say with patch cords, that are very easy to say in imperative (or functional!) code -- and other things that are easy to say in patch cords that are harder in code (such as, my GUIs in SuperCollider usually have some model-view-controller glue underneath -- which is robust but you can't explain it in two sentences like you can explain a pd slider wired up to something).
Ofelia is quite nice for providing access to coding style logic with patches inlets and outlets.
hjh
@jancsika I made a version of [dup] with another coding approach. It should work mostly the same, supports counting for [dup 22] and also supports short styles like [dup 5 15 2] or [dup 2 = 10].
There is actually a trick: As long as the first line is not a single number, it will just assume the first number to be "from", the second number "to" and the third number "step", regardless of other symbols. It assumes "<" or ">" as default, only if it detects a "=" it will add another step. 
@ingox Nice.
Once I added the semicolon-separated message args to hand off to expr, it didn't seem as pressing to allow expressions inside the conditions. At that point it just seemed easier to specify the loop length with a single floatarg and do whatever with "i" in the body.
I think this method of leveraging expr is probably useful for something like [array foreach]
[array foreach e, i;
e * 2;
i;
That is-- for each element of the list, output a list containing the current element multiplied by two, followed by the index.
But I guess you have to name the object something other than "array"...
@jancsika This works (has to have spaces around i ):

On the other hand, all this is just a little bit fancier then [expr]. [loop] + [expr] give the same result:

Oops! Looks like something went wrong!