

Lexical vs Dynamic scope in clojure - chrismcbride
http://info.rjmetrics.com/blog/bid/51652/Lexical-vs-Dynamic-Scope-in-Clojure

======
kyleburton
I think the article is a great explanation. I'm not sure I (exactly) agree
with the conclusion "dynamic vars also breaks referential transparency" -
isn't it the combination of lexical closure (referring to symbols from outside
the function) as well as mutable state that breaks referential transparency?

If I have a function that takes a java collection and returns the count, it
has no referential transparency because the collection is mutable, not
necessarily b/c of how it's operating on its arguments.

Of course this is one of the things I love about Clojure and Rich Hickey's use
of immutability as the default behavior (as often as possible) - much [more]
of the Clojure I write has referential transparency, hardly any of the Java I
wrote did.

Thanks!

Kyle

~~~
lmkg
Dynamically bound values can be thought of as invisible arguments, that are
passed through every function up the call stack. A referentially-transparent
function _only_ depends on its explicit arguments, and will always return the
same value when passed the same arguments. A function that depends on a
dynamically-bound variable may return different values when called with the
same arguments.

Example (Common Lisp syntax, not actually tested):

    
    
      (defvar z 0)
       
      (defun example (x y)
        (declare (special z))
        (+ x y z))
      
      (example 1 2)
      
      ==> 3
      
      (let ((z 10))
        (example 1 2))
      
      => 13
    

In this sample, the function _example_ is not referentially transparent,
because it yields different results when passed the same argument. Note that
this happens without using closures or mutation. _example_ does not close over
the value of _z_ in any way because it is dynamically scoped[1]. There is no
mutation because _z_ is re-bound, which is conceptually different from
mutation. It's effectively creating a new binding with the same name and
different scope; a function called within that scope will look for the value
by name, and find the new binding. The original binding is untouched outside
of this new scope.

[1] This is tautological; The term "closure" is defined to refer to lexical
scoping, and was invented to describe it[2].

[2] Actually, now that I'm writing this, it occurred to me that your confusion
entirely stems from subtleties in the definitions of lexical closure and
bindings. A closure is not any function that refers to symbols outside its
body. The term only refers to functions that use lexical scoping to do so, and
therefore need to "close over" their surrounding data and carry it around with
them. Functions referencing dynamically scoped variables do not need to carry
their data around, because they look up the call stack every time.

To your point, it is "referring to symbols outside the function" that breaks
referential transparency, but dynamic bindings do so in an orthogonal fashion
from closures, and unlike closures do not require mutation to do so.

------
sharkbot
The GHC Haskell compiler also supports dynamically scoped parameters via the
XImplicitParams switch [1]. Type constraints are used to indicate which
variables are propagated to the function.

I've used implicit params in my toy compiler code. While it somewhat
simplified the structure of the code, I could have easily written the program
without them.

[1]
[http://www.haskell.org/ghc/docs/latest/html/users_guide/othe...](http://www.haskell.org/ghc/docs/latest/html/users_guide/other-
type-extensions.html#implicit-parameters)

------
draegtun
For those interested in how Perl does dynamic scoping here is dynamic2.clj in
perl5:

    
    
        use 5.014;
        use warnings;
    
        our ($x, $y) = (2, 2);
    
        sub sum_of_squares {
            my ($a, $b) = @_;
            ($a * $a) + ($b * $b);
        }
    
        sub sum_of_squares_for_x_and_y { sum_of_squares $x, $y }
    
        say sum_of_squares_for_x_and_y;  # => 8
    
        {
            local ($x, $y) = (10, 5);
            no warnings 'redefine';
            local *sum_of_squares = sub {
                my ($a, $b) = @_;
                $a / $b;
            };
        
            say sum_of_squares_for_x_and_y;  # => 2
        }
    
        say sum_of_squares_for_x_and_y;  # => 8
    

PS. I seem to be making a lot of HN comments on dynamic scoping lately :)

<http://news.ycombinator.com/item?id=3446384> |
<http://news.ycombinator.com/item?id=3423631>

