Since we're all in OO land for today, I have a question:
Given this fun piece of Lisp (Scheme) code:
Code:
(define (append! x y)
(set-cdr! (last-pair x) y)
x)
(define (last-pair x)
(if (null? (cdr x))
x
(last-pair (cdr x))))
(define x (list 'a 'b))
(define y (list 'c 'd))
Here's the commented version for those who want to give this one a shot:
Code:
;; Append takes two cons cells (sorta like lists/arrays,
;;but not really, but lists
;; which are used here allow you to do
;;cons-cell stuff to it by default)
;; takes the pairs of x and y (pair is really n-items)
;; and appends x to y,
;;thus ('a 'b 'c) & ('e 'f 'g) => ('a 'b 'c 'd 'e 'f)
;; now create append! which takes two cons x y
;; and appends them together, thus ('a 'b 'c) & ('e 'f 'g) => ('a 'b 'c 'd 'e 'f)
(define (append! x y)
(set-cdr! (last-pair x) y)
x)
;; last pair is a helper function to append!
;;(append is a tail-recursive function)
;; which uses tail recursion to create a single list.
;; look back up to (append!) and notice
;;(set-cdr!(....)), which is a procedure
;; that takes the list (in this case)
;;of x and creates a mutated list.
(define (last-pair x)
(if (null? (cdr x))
x
(last-pair (cdr x))))
;; This of course creates two global variables x and y
(define x (list 'a 'b))
(define y (list 'c 'd))
The output is as follows:
Code:
> (car x)
'a
> (cdr x)
(mcons 'b '())
> (car y)
'c
> (cdr y)
(mcons 'd '())
which all makes sense, and now for plain-ol' append:
Code:
> (define z (append x y))
> z
(mcons 'a (mcons 'b (mcons 'c (mcons 'd '()))))
> (car x)
'a
> (cdr x)
(mcons 'b '())
> (car y)
'c
> (cdr y)
(mcons 'd '())
>
and then append!:
Code:
> (define w (append! x y))
> w
(mcons 'a (mcons 'b (mcons 'c (mcons 'd '()))))
> (car x)
'a
> (cdr x)
(mcons 'b (mcons 'c (mcons 'd '())))
> (car y)
'c
> (cdr y)
(mcons 'd '())
Hopefully you caught the anomaly of (cdr x)
While I understand why this happened (Pen and Paper ftw!), I don't understand why something like this would be needed. Okay, mutable data is obvious, but is there any real-world use where:
-- Create an object
-- Define a new variable w which already has a mutable object x
-- Mutate the object x and store it in w
-- Let mutable and mutated object x hang around freely
I take it the lesson is supposed to be "be wary of mutable data because you may have strange side-effects," but I wonder if there is ever a need to create multiple lines of mutation in a program, or is this strictly a warning to not do this sort of stuff?
One part of the OO programs I have been going through already store the object in the object. For example, one may make create a bank account and have:
(account ('my-account 'withdraw 100))
>> whatever is left provided sufficient funds
and so on and so forth to create further accounts.
But this would be like me asking what the internal x is of procedure account and it telling me that it holds some specified value I can further mutate and this affects all accounts, which isn't supposed to happen. Now that I think of it, this is similar to what I was asking about
: account essentially takes a list and creates a mutable cons cell?
Ugh, I feel like this is so close, but there's something there I can't quite explain to myself or articulate, thus I can't really ask the question, but that free-floating mutated and mutable object is bothering me.
note: Part of the stated lesson here is to demonstrate that visually same is not the same as computer same.