I feel Notebooks aren't used as much because they're a great tool, but that they are used so much as a necessity since you need to look at live data to have any hopes of understanding what's going on. Why couldn't a compiler instead tell me what I'm trying to do will fail?
Last year, I had an in-person discussion with a numpy core developer in which I proposed adding pandas-like syntax to numpy, e.g. allowing the author to use:
a.boolmask[b == c]
(but maybe not so verbose).
A problem immediately arises: An array can have multiple axes, and each could be indexed with a different type within the same slicing call.
One idea might be to allow the author to explicitly wrap the arguments with some dummy class to make clear what types they’re using:
a[np.boolmask(b == c), d, np.intlist(e)]
(Again, perhaps choosing shorter names in practice.)
The idea would be that the wrapper merely “looks like” the thing it wraps, but contains an assertion to verify the type of the argument.
Anyway, I agree that notebooks (or REPLs in general) are great for verifying your assumptions about how little snippets will behave. But I think they would be useful even in a fully statically-typed compiled language, too.