Deep binding binds the environment at the time the procedure is passed as an argument - relevant only for functional languages where functions can be passed as parameter to functions.
x: integer := 1
y: integer := 2
procedure add
x:= x + y
procedure second (P: Procedure)
x: integer := 2
p()
procedure first
y: integer := 3
second (add)
first ()
write_integer(x)
Here, execution starts from line number 11. first() is called and control goes to line number 8. Here a new variable "y" is created (this will hide the global variable "y"). Now second() is called and function "add" is passed as an argument. Due to deep-binding, the scope of variables in "add" gets assigned here. So, usage of "y" in "add" will correspond to the "y" declared in "first" and not the global "y" (if a variable named "y" is declared in "add" that gets preference as usual). Same for variable "x". Now, control goes to "second". A variable "x" is declared here and function p, which is "add" is called. Had we followed shallow binding, due to dynamic scoping, "x" in add will be the "x" in the calling function which is having value 2. But due to deep binding, "x" is already binded to the "global x". So, in function add, global "x" will be updates as $1+3 = 4.$
While Shallow binding binds the environment at the time the procedure is actually called.
Shallow binding just traverses up the activation records until it finds the nearest variable that corresponds to the name.
So, for shallow binding, the update the value as $2+3=5$.
Using dynamic scoping with deep binding value of $x$ will be $4$.