For example, if the JIT has the code "function(a, b) { return a+b; }", and it sees that the function has been called 50 times with a and b as integers, it can generate a machine code implementation that is just a couple of instructions adding two registers.
If you keep the abstractions wide enough to support other values, you can never achieve this efficiency.
The language designer.
> If you're the JIT developer and you define a value encoding that supports all possible values (so that the JITed function never has to be rolled back), then you can't really optimize.
Obviously, the solution is to know the types of values ahead of time. This is precisely where a language with more precise abstractions can make the lives of implementors easier.
(0) They increase the effectiveness of code as a communication medium between programmers. To use an analogy: If I tell you a story, you don't need to hire actors to enact it, just to understand the plot. You can just use your knowledge of the English language, right? Imagine if we could do the same with code: programmers conversing in code, because they understand it natively, without having to “interpret” it (in a REPL, using a test suite, etc.).
(1) They decrease the burden of anticipating, preventing and handling things that may go wrong. Again, to use an analogy: Defensive programming in a language with imprecise abstractions is like spending 75% of a construction project's budget on buying insurance.
The fact that precise abstractions usually lend themselves to simpler and more elegant implementations than imprecise abstractions, well, it is just a nice additional benefit.