# structure of 2/25/21 lecture

### 1. Lambda calc is math. basis of programming lanuguages
#       -- like boolean algebra
#       -- until you get to the problem of STATE (both stateless)
# Destructive assignments introduce "statefulness", but statefulness can
# be encapsulated if only done on bound variables, e.g., loop counters
# introduce only an internal notion of state. But mutating a free variable
# in a closure leads to quite a different phenomenon.

# mention older lecture

# function to create a closure with state
sub makeaccumulator
{
    my $x = $_[0];  # set initial value, must be lexically scoped var
    sub {
	$x += $_[0];
	$x # return this value
    } # return value of makeaccumulator is this lambda-expression
}


my $a1 = makeaccumulator(0);
my $a2 = makeaccumulator(0);
sub println {print join(" ",@_);  print "\n"}

println "a1: ", $a1->(2);
println "a1: ", $a1->(2);
println "a1: ", $a1->(2);
println "a2: ", $a2->(2);
println "a1: ", $a1->(2);
println "a2: ", $a2->(2);  # each closure contains its own copy of x,
# each carries with it it's own STATE.

### Now we can talk about objects as stateful entities.

## But the closure contains only one interface function:


sub newaccumulator {
    my $x = $_[0];  # accumulator, mutable variable set to initial value
    my $x0; # initial value of $x

    my $inc = sub { $x+= $_[0]; $x}; # increment and return new value
    my $mult = sub { $x*= $_[0]; $x}; # multiply by value
    my $reset = sub { $x = $x0; };
    my $transfer = sub {  #transers this accumulator value to other accumulator
	my $other = $_[0]; # get pointer to other accumulator
	$other->("inc")->($x);
	$x = 0;
    };
    # but all these my's are all "super-private"  how to make "public"

    # public interface function
    my $public = sub {
      my ($req,@rest) = @_;  #$_[0];
      if ($req eq "inc") { return $inc } # return pointer to internal lambda
      if ($req eq "reset") { &$reset(); return}
      if ($req eq "mult") { $mult->(@rest); }  # &{$mult}
      if ($req eq "transfer") { return $transfer; }
      println "invalid request";
    };

    $public  # return pointer to public interface
    
}# newaccumulator

my $ac1 = newaccumulator(10);
my $ac2 = newaccumulator(200);
println $ac1->("mult",5);
println $ac1->("inc")->(7);  # now should be 57
$ac1->("transfer")->($ac2);
println $ac1->("inc")->(0);  # now should be ?
println "a2's balance", &$ac2("inc")->(0);  # now should be ?
#

# see accumulator.kt for typical implementation in java-ish oop language
