SICP by Harold & Sussman
modified 20/04/2024 23:55Modularity, objects and state
- software should ideally be modualr – that is, split into multiple components, so they can be developed separately and by different people. to write software like this, we can use the oop mindset, where every concept/physical thing is an object, and a system is just a bunch of objects that communicate together, or the stream strategy, where information just flows in the system.
- the disantvantage of objects is that the state of objects change, so we lose the substitution model of computation, where to evaluate
(f x)
you just plug anything forx
, and you always get the same result for the samex
. - encapsulation is just a function with a local variable that, when called, changes the state of that variable. now we can create variables with local state.
- this way, oop is just dispatch + encapsulated functions – like defining functions in a class
- and for loops are just recursive functions that mutate a variable and verify that its less than some condition
The environment model of substitution
- basicaly, because the substitution model doesnt work anymore (becuse when calling
set!
, it doesn’t modify the state variable in real time, and instead the old version is returned), we need a new model of computation - the environment model is just a sequence of tables, in which there’s variable names and their value. for every variable change, you just add a new table with the modified value. in order to search for the value of a variable in a given point in time, you just look at the last table in which it appeared.
- finding bindings in an environment is like a recursive procedure:
// searching for x look in current environment if last environment: raise error: x is not defined if x in current environment: x is that else: look for x in previous environment
- a procedure is just a pair consisting of body+parameters and pointer to the environment in which it’s defined (you need the pointer, in order to know in what environment it’s been defined). using
define
creates a procedure, but also takes a name and binds that to the procedure in the current environment.- to evaluate a procedure, we create a new frame, where the parameters are bound to the arguments with which the function was called with, and evaluate its body in this new environment.
set!
finds the first frame in which some binding was defined, and changes it to a new value. if it doesnt find it, it doesnt exist, so it raises an error. it makes sense:x = 5 <--- first frame y = x + 3 <--- wil be 8, not 23, as it's evaluated from top to bottom, not from set to top to bottom function f: (set! x 20) function usesx: return x+3 f() <--- some other frame; we'll change the value of x, y won't change, but x will now be 20 in the first frame. the fact that x got modified in the first frame, means that it got modified in all other frames after that. so, in usesx, x will now have the value 20 too.
Modeling with mutable data
- we define a new kind of operations – mutators, that will mutate the data