All of the storage types involve storing something at one point and retrieving it later. To do this in only one operation, you should do either storing or retrieving automatically, and specify the position of the stored value in the other operation.
That is, for explicit storage, you could create an operator to retrieve the nth calculated value before this operation, or put back the current value after n operations. Alternatively, you could use the absolute position from the start of the program, or do more things such as removing some elements automatically after some operations (like in a stack). You could also make multiple operators, retrieving from different copies of the storage with or without these automatic operations. And you should try to make the maximum number needed to specify in the operations reasonably small, so you could assign one operator for each number.
But in most cases, you don't even need an operator and the language will do this implicitly. That is when you need to consider a more standardized model such as stacks or queues. The most successful for now seemed to be tacit programming, which doesn't even mention storage directly.
If you want to design a new such model, you could try expanding the evaluations as a dag, and try to think of a default dag if nothing else is specified. Most likely, the default is just a tree, except for that multiple leaves may be linked to the same input. You could for example use a queue for a balanced tree, or a stack for a deep tree where leaves are mostly constant, or something like Jelly for a deep tree where leaves are mostly copies of the input.
But note that, you could encode the shape of a binary tree in only 2 bits per operator. So, if your language has less than 64 operators, you may actually ignore the traditional models and just encode the complete tree in the spare bits (call them combine_parent and below_leaf flags). Even if there are more operators, you could make a fairly good default (such as the model of Jelly) and 3 modifiers to change it.
You could use the same model for implicit and explicit storage for convenience, but you don't have to. For example, you could use a stack for implicit storage, but don't pop elements in the explicit storage (or in another explicit storage in addition to the implicit one). It's likely it won't be called a stack in the final documentation, but you get the idea.
For reference, the size of the perfect encoding of a binary tree is the logarithm of the Catalan numbers. And the size of the perfect encoding of a "binary" dag is the logarithm of A082161, but obviously impractical. This assumes an operator with different argument order two different operators, adding another bit when it is not.
Sometimes you may still want variables for the loops. It might be possible to rewrite the loops in other ways. But if you really need it, don't use a 1-byte construct in addition to a name to define the variable. unless you are only using the preinitialized values, it's usually more efficient to use a 1-bit flag to specify whether you are reading or writing this variable.