# The nonlocal statement def make_withdraw(balance): """Return a functional representation of a bank account. >>> withdraw = make_withdraw(100) >>> withdraw(25) 75 >>> withdraw(25) 50 >>> withdraw(60) 'Insufficient funds' >>> withdraw(15) 35 """ def withdraw(amount): nonlocal balance if amount > balance: return 'Insufficient funds' balance = balance - amount return balance return withdraw # Local state using mutable data type def make_withdraw_list(balance): """Return a functional representation of a bank account. >>> withdraw = make_withdraw_list(100) >>> withdraw(25) 75 >>> withdraw(25) 50 >>> withdraw(60) 'Insufficient funds' >>> withdraw(15) 35 """ b = [balance] def withdraw(amount): if amount > b[0]: return 'Insufficient funds' b[0] = b[0] - amount return b[0] return withdraw # Create two withdraw functions def two_withdraws(): """Show that two calls to make_withdraw produce different accounts. >>> wd = make_withdraw(100) >>> wd2 = make_withdraw(100) >>> wd(25) 75 >>> wd2(15) 85 """ pass # Multiple references to a withdraw function def same_withdraws(): """Show that two references to the same withdraw function affect the same account. >>> wd = make_withdraw(100) >>> wd2 = wd >>> wd(25) 75 >>> wd2(15) 60 """ pass # Referential transparency def reftrans(): """Show that replacing an expression that has side effects with its value provides different results. >>> wd = make_withdraw(100) >>> wd(25) + wd(15) 135 >>> 75 + 85 160 """ pass # Mutable container def container(contents): """Return a container that is manipulated by two functions. >>> get, put = container('hello') >>> get() 'hello' >>> put('world') >>> get() 'world' """ def get(): return contents def put(value): nonlocal contents contents = value return get, put # Dispatch functions def pair(x, y): def dispatch(m): if m == 0: return x elif m == 1: return y return dispatch def container_dispatch(contents): """Return a container that is manipulated by a dispatch function. >>> c = container_dispatch('hello') >>> c('get') 'hello' >>> c('put', 'world') >>> c('get') 'world' """ def dispatch(message, value=None): nonlocal contents if message == 'get': return contents elif message == 'put': contents = value return dispatch # Immutable rlist empty_rlist = None def rlist(first, rest): return pair(first, rest) def first(s): return s(0) def rest(s): return s(1) def len_rlist(s): if s == empty_rlist: return 0 return 1 + len_rlist(rest(s)) def getitem_rlist(s, k): if k == 0: return first(s) return getitem_rlist(rest(s), k - 1) def rlist_to_tuple(s): if s == empty_rlist: return () return (first(s),) + rlist_to_tuple(rest(s)) def str_rlist(s): return '' # Mutable rlist def mutable_rlist(): """An rlist that supports push and pop operations. >>> lst = mutable_rlist() >>> lst('len') 0 >>> lst('push', 4) >>> lst('len') 1 >>> lst('push', 5) >>> lst('len') 2 >>> lst('str') '' >>> lst('getitem', 1) 4 >>> lst('pop') 5 >>> lst('str') '' """ contents = empty_rlist def dispatch(message, value=None): nonlocal contents if message == 'first': return first(contents) if message == 'rest': return rest(contents) if message == 'len': return len_rlist(contents) if message == 'getitem': return getitem_rlist(contents, value) if message == 'str': return str_rlist(contents) if message == 'pop': item = first(contents) contents = rest(contents) return item if message == 'push': contents = rlist(value, contents) return dispatch