##############################################################
#
#  Implicit as opposed to declared local variable
#  (together with scoping) lead to some unnatural
#  (i.e. non-lexically scoped) behaviour.
#  
#  Solution is mostly to explicitly pass the variables 
#  along in the function call. i.e. maintain control of them.
#
#  Here is the simplest version.
#

x <- 1:4
y <- x * 10
foo <- function(x) {
           y    <- x    + y
      #    ^local  ^local ^global
      # left of the assignment, y is local, right it is global
           y    <- x    + y
      #    ^local  ^local ^local
      # from now on, y is local everywhere.
         list(x=x,y=y)
        }

foo(x)

#
# Note the value of y
#
# Note also that the value of y outside of foo is not
# changed.  This is important.

y


#
#  This can have subtle negative effects, particularly with locally
#  defined functions where lexical scoping seems natural.
#  Eg.  putting the above together, ...

foo <- function(x) {
            z <- x * 10
            y <- z * 10
            w <- y * 10
            bar <- function(x) {
                      z <- x + z  
                      y <- x + y
                      list(barx =x, bary = y, barz = z)
                      }
           # One might call bar to add x to z and y
           barw <- bar(w) 
           # but outside of bar these would not have changed.
           list(wfoo = w, xfoo= x, yfoo= y, zfoo= z, barw = barw)
          }

foo(x)
# Had z and y been treated globally on both sides of the assignment
# within bar they would would have been updated within foo.
#
# The solution might be that the local function, bar, needs to pass
# y and z as well as the value for x.
# Here is a first attempt.

foo <- function(x) {
            z <- x * 10
            y <- z * 10
            w <- y * 10
            bar <- function(x,y,z) {
                      z <- x + z  
                      y <- x + y
                      list(barx =x, bary = y, barz = z)
                      }
           # One might call bar to add x to z and y
           barw <- bar(w,y,z) 
           # but outside of bar these would not have changed.
           list(wfoo = w, xfoo= x, yfoo= y, zfoo= z, barw = barw)
          }

foo(x)

#
# which unfortunately does not have the desired effect.
# These changes cannot be had by side effect, they must
# be done by assigning the results of the function evaluation
# as in
#

foo <- function(x) {
            z <- x * 10
            y <- z * 10
            w <- y * 10
            bar <- function(x,y,z) {
                      z <- x + z  
                      y <- x + y
                      list(barx =x, bary = y, barz = z)
                      }
           # One might call bar to add x to z and y
           barw <- bar(w,y,z)
           # Now do the assignment.
           y <- barw$bary
           z <- barw$barz
           # but outside of bar these would not have changed.
           list(wfoo = w, xfoo= x, yfoo= y, zfoo= z, barw = barw)
          }

foo(x)


# which brings us to the following (unattractive) solution
# as simpler but which mixes local and parent values for
# y and z within bar.

foo <- function(x) {
            z <- x * 10
            y <- z * 10
            w <- y * 10
            bar <- function(x) {
                      z <- x + z  
                      y <- x + y
                      list(barx =x, bary = y, barz = z)
                      }
           # One might call bar to add x to z and y
           barw <- bar(w)
           # Now do the assignment.
           y <- barw$bary
           z <- barw$barz
           # but outside of bar these would not have changed.
           list(wfoo = w, xfoo= x, yfoo= y, zfoo= z, barw = barw)
          }

foo(x)

########################################################################
#
# Perhaps a more natural example where these concerns would arise
# would be something like

x
foo <- function(x) {
            swap <- function(i,j) {
                      tmp  <- x[i]  
                      x[i] <- x[j]
                      x[j] <- tmp
                      }
           # One might call swap, hoping to interchange a pair of values
           # within the vector x. (usually this would be buried in a loop)
           swap(1,2)
           # but it won't work.
           list(xfoo= x)
          }

foo(x)

# Note that the swap function does not explicitly pass x
# and referred only to two elements of x.
# Nevertheless, the local x has (seemingly) inherited the entire
# structure of the parent x, its length for example

x
foo <- function(x) {
            swap <- function(i,j) {
                      tmp  <- x[i]  
                      x[i] <- x[j]
                      x[j] <- tmp
                      print(length(x))
                      }
           # One might call swap, hoping to interchange a pair of values
           # within the vector x. (usually this would be buried in a loop)
           swap(1,2)
           # but it won't work.
           list(xfoo= x)
          }

foo(x)

#
# which means that all of x was copied within swap, even
# though only two elements were accessed.

#
# You might think that the solution is to simply make x an argument
# to swap
#
x
foo <- function(x) {
            swap <- function(x,i,j) {
                      tmp  <- x[i]
                      x[i] <- x[j]
                      x[j] <- tmp
                      }
           # One might call swap, hoping to interchange a pair of values
           # within the vector x. (usually this would be buried in a loop)
           swap(x,1,2)
           # but it still won't work.
           list(xfoo= x)
          }

foo(x)

#
# which still does not work.  This might have been guessed since
# the version without passing x still had access to the entire 
# structure of x (length, elements, etc.)

# The solution is had by returning the local x as the value of the function
# (as before).  N.B. There is no need to have x appear as an argument
# to the internal function here.

x
foo <- function(x) {
            swap <- function(i,j) {
                      tmp  <- x[i]  
                      x[i] <- x[j]
                      x[j] <- tmp
                      x
                      }
           # One might call swap, hoping to interchange a pair of values
           # within the vector x. (usually this would be buried in a loop)
           # NOW assign the result back to x.
           x <- swap(1,2)
           # Unfortunately, this produces a lot of copying which is
           # not so good if x is large.
           list(xfoo= x)
          }

foo(x)

# This works but seems to be very bad style.
# 

################################################################################
#
# Many programming languages are lexically scoped and so
# transcribing a program from one such language to the S
# language needs to be done with care.
#
################################################################################
#
# Here is an example of the quicksort algorithm (doubly recursive)
# taken from http://math.uww.edu/~harrisb/courses/cs171/sorts.html
# Language is TURBO PASCAL (here as a string, so that it can be harmlessly
# evaluated).

"
PROCEDURE quick (var arr:list; max:integer);

PROCEDURE sort(l,r: integer);
VAR
  i, j : integer;
  x : string;
BEGIN
  i := l;
  j := r;
  x := arr[(l+r) DIV 2];
  REPEAT
    WHILE arr[i]<x DO
      i := i+1;
    WHILE x<arr[j] DO
      j := j-1;
    IF i<=j THEN
      BEGIN
        swap(arr[i],arr[j]);
        i := i+1;
        j := j-1;
      END;
  UNTIL i>j;
  IF l<j THEN
    sort(l,j);
  IF i<r THEN
    sort(i,r);
END;

BEGIN {quicksort};
  sort(1,max);
END; 
"
#
# An a transliteration tweaked to work in S.
# quick --> quicksort
# sort --> mysort ... note that x is passed and returned in the S version.
# A simple transliteration would fail.
#
quicksort <- function (x, max=length(x)) {
                ## implemented (doubly) recursively 
                mysort <- function(x,l,r) {  # scoping rules of R/S require that
                                             # x be passed as an argument,
                                             # otherwise value of x in
                                             # the environment at the time of
                                             # definition of mysortup is used  ... rwo
                  i <- l
                  j <- r
                  h <- x[floor((l+r)/2)]  ## div 2
                  
                  repeat {
                    while(x[i] < h) {i <- i+1}
                    while(h < x[j]) {j <- j-1}
                    if(i<=j) {
                        ## swap x[i] and x[j]
                        tmp <- x[i]
                        x[i] <- x[j]
                        x[j] <- tmp
                        i <- i+1
                        j <- j-1
                        } ## end if
                    if(i > j) {break()} else {next()}
                  } ## end repeat

                  if(l < j) {mysort(x,l,j)}
                  if(i < r) {mysort(x,i,r)}

                x} ## end of mysort
                                             # need to return x inside mysortup
                                             # or it will be lost since x outside
                                             # was not altered.  ... rwo

              mysort(x,1,max)
                }

quicksort(5:1)