1 / 35

Functional Programming

Functional Programming. Universitatea Politehnica Bucuresti 2008-2009 Adina Magda Florea http://turing.cs.pub.ro/fp_09. Lecture No. 3. Objects and pointers Objects on the heap Reclaiming the memory Dynamic typing Lexical scope Procedures. 1. Objects and pointers. Variables

dennisi
Download Presentation

Functional Programming

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Functional Programming Universitatea Politehnica Bucuresti2008-2009 Adina Magda Florea http://turing.cs.pub.ro/fp_09

  2. Lecture No. 3 • Objects and pointers • Objects on the heap • Reclaiming the memory • Dynamic typing • Lexical scope • Procedures

  3. 1. Objects and pointers • Variables • allocated statically (as in the case of global variables) • on an activation stack as part of a procedure activation record (as in the case of local variables) • dynamically allocated on the heap at run time using an allocation routine (like malloc or new in other pl)

  4. 2. Objects on the heap • All Scheme objects are allocated on the heap, and referred to via pointers • A procedure takes pointers to the arguments and returns a pointer to the value computed and returned by the procedure • Procedures always dereference a pointer to a value when they really use the value - you never have to explicitly force the dereferencing.

  5. Objects on the heap • (+ 2 3) 5 • Most Scheme implementations optimize a lot of pointers. • Tagging - the value in each variable actually has a few bits devoted to a type tag

  6. Objects on the heap • Numbers - you can't change the state of the object itself. • There's no way to side-effect an integer object and make it behave differently. • We say that integers are immutable, i.e., you can't mutate (change) them. • If integers were actually allocated on the heap and referred to via pointers, and if you could change the integer's value, then that change would be visible through other pointers to the integer.

  7. Objects on the heap • Most Scheme objects only have fields that are general-purpose value cells • Any field can hold any Scheme value, whether it's a tagged immediate value or a tagged pointer to another heap-allocated object. • In most implementations, each heap-allocated object has a hidden "header" field

  8. header pair-id foo car 15 cdr 22 Objects on the heap • Cons cell (pair) • (define foo (cons 15 22)) • set-car!, set-crd!

  9. 3. Reclaiming the memory • The Scheme heap is garbage collected • The collector will never take back any object that your program holds a pointer to, or might reach via any path of pointer traversals • The use of garbage collection supports the abstraction of indefinite extent. • All objects conceptually live forever, or at least as long as they might matter to the program. • From the point of view of a running program, memory is infinite - it can keep allocating objects indefinitely, without ever reusing their space.

  10. 4. Dynamic typing • In Scheme, all variables have the same type: "pointer to anything." • Scheme is dynamically typed • Variables don't have fixed types, but objects do. • An object carries its type around with it • The language provides type-checking at run time to ensure that you don't perform the wrong operations on objects • In dynamically typed systems, types are enforced at runtime.

  11. 5. Lexical scope • Scheme is a block-structured language with nested scopes. • Scheme uses a lexical scope rule. • Scheme is statically scoped, rather than dynamically scoped, like Lisp. • If nested lets define variables by the same name, then the uses of that name in the body of the inner let will refer to the bindings created by the inner let.

  12. Lexical scope (let ((x 10) ; outer binding of x (a 20)) ; binding of a (foo x) (let ((x (bar)) ; inner binding of x (b (baz x x))) ; binding of b (quux x a) (quux y b)) (baz x a) ; refers to outer x (and a) (baz x b)) ; illegal? inner let variable x shadows the outer one

  13. Lexical scope • The set of all bindings that are visible at a given point during program execution is called a binding environment. • Top-level binding environment - hash table • With local variables, a simple "flat" table isn't sufficient. • Each binding construct introduces a new binding contour - it changes the "shape" of the environment.

  14. Lexical scope • At any given point, the environment consists of all of the variable bindings that are visible. • This includes all of the bindings in the table for the innermost contour, and all of the bindings in the table for the contours it's nested inside, except those that are shadowed by inner bindings of the same names.

  15. Lexical scope (let ((x 10) (a 20)) (foo x) (let ((x (bar)) (b (baz x x))) (quux x a) (quux y b)) (baz x a) (baz x b)) scope of outer x and a scope of inner x and b

  16. Lexical scope (let ((a-structure (some-procedure))) (let ((a-substructure (get-some-subpart a-structure))) (let ((a-subsubstructure (get-another-subpart a-substructure))) (foo a-substructure)))) (let ((a-structure (some-procedure)) (a-substructure (get-some-subpart a-structure)) (a-subsubstructure (get-another-subpart a-substructure))) (foo a-substructure)) (let* ((a-structure (some-procedure)) (a-substructure (get-some-subpart a-structure)) (a-subsubstructure (get-another-subpart a-substructure))) (foo a-substructure)) scope of all three variables

  17. 6. Procedures • Scheme procedures are "first class," meaning that they're objects in the language. • They can be anonymous, meaning that you can have pointers to procedures that don't have printed names. • They can be higher-order, meaning that procedures can operate on procedures.

  18. 6.1 Procedures - first-class objects • Procedures "first class" objects = • you can pass a procedure value as an argument to a procedure, return it as the value of a procedure call, store it in a variable or a field of another object. • A procedure pointer is just a value that you can pass around like any other value, like a pair or a boolean.

  19. Procedures - first-class objects • A procedure call expression is called a combination. • Evaluation of a combination includes evaluation of the argument expressions and application of the procedure to the arguments. • Scheme uses a unified namespace = there's only one kind of name for both normal variables and procedures • In fact, procedure names are really just variable names, and there's only one kind of variable. • A named procedure is really just a first-class procedure object that happens to be referenced from a variable.

  20. Procedures - first-class objects (define (min a b) (if (< a b) a b)) (min 3 5) => 3 (define min +) (min 3 5) => 8

  21. 6.2 Lambda expressions (define (double x) (+ x x)) is exactly equivalent to (define double (lambda (x) (+ x x))) • In either case, we're creating a one-argument procedure, and we're also defining and binding a variable named double, and initializing its storage with a pointer to the procedure. • The procedure-defining syntax for define is just syntactic sugar--there's nothing you can do with it that you can't do with local variables and lambda.

  22. Lambda exp and lexical scope • Lambda creates a procedure that will execute in the scope where the lambda expression was evaluated. • Except for local variables of the procedure itself, including its arguments, names in the body of the procedure refer to whatever they refer to at the point where the procedure is created by lambda. • This is necessary for preserving lexical scope • Lambda creates a closure, a procedure whose free variable references are "fixed" at the time the procedure is created. • Whenever the procedure references a free variable, it will refer to the bindings of those variables in the environment where the procedure was created.

  23. Lambda exp and lexical scope (define foo 1) (define (baz) foo) (define (quux) (let ((foo 6)) (baz))) (quux) • The procedure bazreturns to the environment where it was created before it executes, and even before it binds its arguments – lexical scope • LISP – dynamic scope

  24. Lambda exp for local definitions of procedures • Scheme lets you define local procedures, scoped inside other procedures or blocks with local variables. • You can define local procedures using let and lambda (define (quadruple x) (let ((double (lambda (x) (+ x x)))) (double (double x))))

  25. Local definitions (define (quadruple x) (let ((double (lambda (x) (+ x x)))) (double (double x)))) (define (quadruple x) (define (double x) ; define a local procedure double (+ x x)))) (double (double x)))) ; nested calls to the local procedure There's a restriction on internal defines They must be at the beginning of the procedure body - or the beginning of another body, like a let body, before the normal executable expressions in the body.

  26. Local definitions • Local procedure definitions follow the normal lexical scope rule, like nested lets. (define (quadruple x) (define (double x) ; define a local procedure double (+ x x)))) (double (double x)))) ; nested calls to the local procedure scope of x scope of double

  27. Recursive local definitions local variable local-proc isn't visible to the lambda expression (define (foo x) (let ((local-proc (lambda (y) ... (local-proc ...) ; recursive call? No. ...))) ... (local-proc x) ...) scope of y scope of local-proc

  28. Recursive local definitions (define (foo x) (letrec ((local-proc (lambda (y) ... (local-proc ...) ; recursive call? Yes. ...))) ... (local-proc x) ...) scope of y scope of local-proc

  29. Recursive local definitions (define (foo) (letrec ((countdown (lambda (i)                      (if (= i 0) 0                          (begin                            (display i)                            (newline)                            (countdown (- i 1)))))))  (countdown 10)))

  30. High-order procedures • Scheme is designed to make it easy to use higher-order procedures • i.e., procedures that may take other procedures as arguments or return them as values. (sort < '(5 2 3)) => (2 3 5). (sort > '(5 2 3)) => (5 3 2) (sort string<? '("foo" "bar" "baz" "quux")) => ("bar" "baz" "foo" "quux")

  31. High-order procedures - map • (map proc list1 list2 ...)  (map cadr '((a b) (d e) (g h))) => (b e h) (map (lambda (x) (+ x 1)) '(1 2 3)) => (2 3 4) (map (lambda (n) (expt n n)) '(1 2 3 4 5)) => (1 4 27 256 3125) (map + '(1 2 3) '(4 5 6)) => (5 7 9)

  32. High-order procedures - map (define (map1 proc lis) (cond ((null? lis) '()) ((pair? lis) (cons (proc (car lis)) (map1 proc (cdr lis)))))) (map1 (lambda (x) (+ x 1)) '(1 2 3)) => (2 3 4)

  33. High-order procedures - map (define (first-name name) (car name)) (define (first-name-list name-lis) (cond ((null? name-lis) ()) (else (cons (caar name-lis) (first-name-list (cdr name-lis)))))) (first-name '(maria petrescu)) => maria (first-name-list '((maria petrescu) (gigel popescu) (john smith))) => (maria gigel john) (mapfirst-name '((maria petrescu) (gigel popescu) (john smith))) => (maria gigel john)

  34. High-order procedures – for-each • (for-each proc list1 list2 ...) (let ((v (make-vector 5)))   (for-each (lambda (i)               (vector-set! v i (* i i)))             '(0 1 2 3 4))   v) => #5(0 1 4 9 16) (for-each (lambda (x) (+ x 1)) '(1 2 3)) =>

  35. High-order procedures – for-each (define (for-each1 proc lis) (cond ((null? (cdr lis)) ; one-element list? (proc (car lis))) (else (proc (car lis)) (for-each1 proc (cdr lis))))) (for-each1 (lambda (x) (+ x 1)) '(1 2 3)) => 4

More Related