What Stanley meant by “recursive” is just that the operator is applied to every returned object until the returned type is a pointer.
Which happens here on the first try: screen::operator -> returns a pointer. Thus this is the last call to an operator -> that the compiler attempts. It then resolves the right-hand sice of the operator (p) by looking up a member in the returned pointee type (dummy) with that  name.
Essentially, whenever the compiler finds the syntax aᵢ->b in code, it essentially applies the following algorithm:
- Is 
aᵢ of pointer type? If so, resolve member b of *aᵢ and call (*aᵢ).b. 
- Else, try to resolve 
aᵢ::operator ->
- On success, set 
aᵢ₊₁ = aᵢ::operator ->(). Goto 1. 
- On failure, emit a compile error.
 
 
I’m hard-pressed to come up with a short, meaningful example where a chain of operator -> invocations even makes sense. Probably the only real use is when you write a smart pointer class.
However, the following toy example at least compiles and yields a number. But I wouldn’t advise actually writing such code. It breaks encapsulation and makes kittens cry.
#include <iostream>
struct size {
    int width;
    int height;
    size() : width(640), height(480) { }
};
struct metrics {
    size s;
    size const* operator ->() const {
        return &s;
    }
};
struct screen {
    metrics m;
    metrics operator ->() const {
        return m;
    }
};
int main() {
    screen s;
    std::cout << s->width << "\n";
}