The general rule is that arguments are evaluated in order, from left to right, after which the resulting values are passed to the function being called. This is called "strict evaluation" and is what happens in your case: the predicate is evaluated first, then e1, then e2, and only after that the logic of your function is applied on these arguments (i.e. after e1 and e2 have already been evaluated, so there's no way of controlling it from within the function).
The strict evaluation order is inadequate for 'if', as you would want the 'then' and 'else' argument only to be evaluated when necessary.
(define (fib n) (if (< n 2) n (+ (fib (- n 1)) (fib (- n 2)))))(fib 10)
Using strict evaluation, the 'else'-part would be evaluated each time (as would the 'then'-part of course), regardless of the condition, and the function would go off computing fibonacci for n going into the far negative, and you've got yourself an infinite computation on your hands (at least until your computer runs out of resources).
'if' needs to be "special", hence it has been promoted to one of the few "special forms" present in Scheme. These special forms have a different evaluation order, a non-strict one, where arguments are
not evaluated immediately, but only when necessary, which is exactly what we need in our case.
You can't add your own special forms (what is possible though, is to make use of macros, which allow you to fine-tune the evaluation order, but that is an advanced topic). Functions you define will always be subjected to the strict evaluation order, and hence it is impossible for you to define a new if (or cond, or while-loop, or any other concept that needs to control how many times its arguments are evaluated).
You can fake it though by manually wrapping expressions in lambda's each time:
(define (my-if pred then else) (if pred (then) (else)))(define (fib n) (my-if (< n 2) (lambda () n) (lambda () (+ (fib (- n 1)) (fib (- n 2))))))
but this is hardly elegant.
The reason the standard chose for strict evaluation order is possibly because it's the most efficient, most common and easiest to understand. Haskell is one of the few languages which strays from this path and offers non-strict evaluation by default, and it can afford that because of the language being purely functional. Using default non-strict evaluation in a language with side-effects would lead to chaos I'd guess.
If I remember correctly, a later chapter in SICP will be discussing an interpreter for a variant of Scheme where you can explicitly control the evaluation strategy for each of the arguments of a function you define.