39
Functional Functional Programming Programming Universitatea Politehnica Bucuresti 2007-2008 Adina Magda Florea http://turing.cs.pub.ro/ fp_08

Functional Programming

  • Upload
    mulan

  • View
    40

  • Download
    0

Embed Size (px)

DESCRIPTION

Functional Programming. Universitatea Politehnica Bucuresti 2007-2008 Adina Magda Florea http://turing.cs.pub.ro/fp_08. Lecture No. 2. S-expressions Data types Defining variables and procedures Special forms Local variables Control constructs Objects and pointers. 1. S-expressions. - PowerPoint PPT Presentation

Citation preview

Page 1: Functional Programming

Functional ProgrammingFunctional Programming

Universitatea Politehnica Bucuresti2007-2008

Adina Magda Florea

http://turing.cs.pub.ro/fp_08

Page 2: Functional Programming

Lecture No. 2

S-expressions Data types Defining variables and procedures Special forms Local variables Control constructs Objects and pointers

Page 3: Functional Programming

1. S-expressions

In Scheme, there's no distinction between expressions and statements

They're all "expressions" – s-expressions Scheme expressions combine the features of

expressions and statements. S-expressions return values However, they can also have side effects

Page 4: Functional Programming

2. Data types in Scheme Simple types: booleans, numbers, characters, and

symbolsBooleans #t for true and #f or () for false boolean? - checks if its argument is booleanNumbers integers (eg, 42), rationals (22/7), reals (3.1416), or

complex (2+3i) Predicates: number? complex? real? rational? integer? eqv? =, <, <=, >, >= self-evaluating

Page 5: Functional Programming

Simple types: Characters

Characters Character data - represented by prefixing the character with #\

char?

(char? #\c) => #t(char? 1) => #f(char? #\;) => #t

char=?, char<?, char<=?, char>?, char>=?

(char=? #\a #\a) => #t(char<? #\a #\b) => #t(char>=? #\a #\b) => #f To make the comparisons case-insensitive, use char-ci (=?...)

self-evaluating

Page 6: Functional Programming

Simple types: Symbols

Symbols(symbol? 'xyz) => #t(symbol? 42) => #f (eqv? 'Calorie 'calorie) => #t (define xyz 9) xyz => 9 We can use the form set! (pronounced "set-bang") to

change the value held by a variable:(set! xyz #\c) xyz => #\c

- are identifiers- are evaluated(unless quote is used)

mutation procedure

Note on type

You should not use assignments a lot in Scheme programs.It's usually a sign of bad style

Page 7: Functional Programming

Structured types: Strings

Strings"Hello, World!" => "Hello, World!"

(string #\h #\e #\l #\l #\o) => "hello"

(define greeting "Hello; Hello!")

(string-ref greeting 0) => #\H New strings can be created by appending other

strings:(string-append "E " "Pluribus " "Unum") => "E

Pluribus Unum"

Page 8: Functional Programming

Structured types: Strings

Make a string of a specified length, and fill it with the desired characters later.

(define a-3-char-long-string (make-string 3)) string? Strings obtained as a result of calls to string,

make-string, and string-append are mutable.(define hello (string #\H #\e #\l #\l #\o))

hello => "Hello"

(string-set! hello 1 #\a) hello => "Hallo"

Page 9: Functional Programming

Structured types: Vectors

Vectors(vector 0 1 2 3 4) => #(0 1 2 3 4)(define v (make-vector 5))(set! v #(1 2 3 4 6))v => #5(1 2 3 4 6)(vector? #(1 2 3)) => #t(vector-ref #(1 2 3) 0) => 1(vector-ref #(1 2 3) 3) =>

vector-ref: index 3 out of range [0, 2] for vector: #3(1 2 3)

(vector-set! v 1 10)v => #5(1 10 3 4 6)

Page 10: Functional Programming

Structured types: Dotted pairs A dotted pair is a compound value made by

combining any two arbitrary values into an ordered couple.

(cons 1 #t) => (1 . #t)(define x (cons 1 #t))(car x) => 1(cdr x) => #t(set-car! x 2)(set-cdr! x #f)x => (2 . #f)(define y (cons (cons 1 2) 3))y => ((1 . 2) . 3)

(car (car y)) => 1(cdr (car y)) => 2(caar y) => 1(cdar y) => 2

Page 11: Functional Programming

Structured types: Lists The abbreviation for a dotted pair of the form

(1 . (2 . (3 . (4 . ())))) is (1 2 3 4) This special kind of nested dotted pair is called a

list (cons 1 (cons 2 (cons 3 (cons 4 '()))))(list 1 2 3 4) => (1 2 3 4)(define y (list 1 2 3 4))(list-ref y 0) => 1(list-ref y 3) => 4(list-tail y 1) => (2 3 4)(list-tail y 3) => (4)

Page 12: Functional Programming

Structured types: Lists The predicates pair?, list?, and null? check if their

argument is a dotted pair, list, or the empty list, (pair? '(1 . 2)) => #t(pair? '(1 2)) => #t(pair? '()) => #f(list? '()) => #t(null? '()) => #t(list? '(1 2)) => #t(list? '(1 . 2)) => #f(null? '(1 2)) => #f(null? '(1 . 2)) => #f

Page 13: Functional Programming

Structured types: Lists List of pairs:

car field hold the pointers to the object

cdr field link the pairs together into a "spine."

A list is really just a sequence of pairs, ending with a null pointer.

A null pointer is a list, too - it's a sequence of zero pairs ending in a null pointer.

An object can easily be in many lists at once, because a list is really just a spine of pairs that holds pointers to the items in the list.

pairfoo

pair pair

22 13 15

pairbar

pair

Page 14: Functional Programming

Lists and quote quote takes exactly one argument, and

returns a data structure whose printed representation is the same as what you typed in as the argument to quote.

Scheme does not evaluate the argument to quote as an expression - it just gives you a pointer to a data structure.

For example, the expression(define foo (quote (1 2 3)))defines (and binds) a variable foo, and initializes

its binding with (a pointer to) a three-element list.

Page 15: Functional Programming

Lists and quote

(define (foo) '(1 2 3)) The list (1 2 3) may be created when we

define the procedure foo, and each time we call it, it may return a pointer to that same list.

For this reason, it's an error to modify a data structure returned from a quote form.

If we want the procedure foo to return a new list (1 2 3) every time, we can write

(define (foo) (list 1 2 3))

Page 16: Functional Programming

Some list procedureslength(define (my-length lis) (cond ((null? lis) 0) (else (+ 1 (my-length (cdr lis))))))

append(define (my-append lis1 lis2) (cond ((null? lis1) lis2) (else (cons (car lis1) (my-append (cdr lis1) lis2)))))

(my-append '(a b c) '(x y)) => (a b c x y)(my-append '((a b) c (d e)) '(x (y z) t)) => ((a b) c (d e) x (y z) t)

Page 17: Functional Programming

Some list procedures append concatenates the lists it is given. It only concatenates the top-level structure, however - it

doesn't "flatten" nested structures. append doesn't modify any of its arguments, but the

result of append generally shares structure with the last list it's given.

It effectively conses the elements of the other lists onto the last list to create the result list.

It's therefore dangerous to make a "new" list with append and then modify the "old" list.

This is one of the reasons side effects are discouraged in Scheme.

Page 18: Functional Programming

Some list proceduresCopying lists

There are two common senses of copying, shallow copying, and deep copying.

Shallow copy

(define (pair-copy pr)

(cons (car pr) (cdr pr)))

Page 19: Functional Programming

Some list proceduresCopying lists

Deep copy

(define (pair-tree-deep-copy thing)

(if (not (pair? thing))

thing

(cons (pair-tree-deep-copy (car thing))

(pair-tree-deep-copy (cdr thing)))))

Page 20: Functional Programming

Some list proceduresCopying lists

(define (list-copy lis)

(cond ((null? lis) '())

(else (cons (car lis) (list-copy (cdr lis))))

Page 21: Functional Programming

Structured types: Procedures

Primitives and procedures The variable denoting a Scheme primitive or a

defined procedure holds that procedure

cons => #<primitive:cons>

car => #<primitive:car>

list-sum => #<procedure:list-sum> When you write a procedure that modifies its

arguments, rather than just returning a value, it's good style to give it a name that ends with !

e.g. reverse vs reverse!

Page 22: Functional Programming

Non-distructive reverse

(define (my-reverse lis)

(cond ((null? lis) ())

(else

(append (my-reverse (cdr lis))

(list (car lis))))))

(define m '(a b c))

(my-reverse m) => (c b a)

m => (a b c)

Page 23: Functional Programming

Distructive reverse; returns the last element of a list; to be used in my-reverse!(define (all-but-last lis) (cond ((null? lis) ()) ((null? (cdr lis)) ()) (else (cons (car lis) (all-but-last (cdr lis))))))

;my-reverse! distroys the initial list by reversing it(define (my-reverse! lis) (let ((l ()) (len (length lis))) (cond ((null? lis) ()) (else (set! l (list-ref lis (- len 1)))

(set-cdr! lis (my-reverse! (all-but-last lis))) (set-car! lis l) lis))))

(all-but-last '(a b c)) => (a b)(define m '(a b c))(my-reverse! m) => (c b a)m => (c b a)

Page 24: Functional Programming

Mind that …; my-rev! seems to destroy the initial list but in fact it does not(define (my-rev! lis) (cond ((null? lis) ()) (else (set! lis (append (my-rev! (cdr lis))

(list (car lis)))) lis)))

(define m '(a b c))(my-rev! m) => (c b a)m => (a b c)

Page 25: Functional Programming

Ports

Yet another data type is the port. A port is the conduit through which input

and output is performed. Ports are usually associated with files and

consoles.

Page 26: Functional Programming

3. Defining variables and procedures

Defining a variable : (define my-variable 5) - tells Scheme to allocate

space for my-variable, and initialize that storage with the value 5. In Scheme, you always give a variable an initial value, so

there's no such thing as an uninitialized variable or an unininitialized variable error.

Scheme values are always pointers to objects e.g., when we use the literal 5, Scheme interprets that as

meaning a pointer to the object 5. Numbers are objects you can have pointers to, just

like any other kind of data structure.

Page 27: Functional Programming

Defining variables

The define expression does three things: It declares to Scheme that we're going to have a

variable named foo in the current scope. It tells Scheme to actually allocate storage for the

variable. The storage is called a binding. It tells Scheme what initial value to put in the

storage. You can not use set! on a variable that has

not been defined

Page 28: Functional Programming

Defining procedures

Defining a procedure: Use the special form lambda to defined an

un-named procedure(lambda (x) (+ x 2)) ((lambda (x) (+ x 2)) 5) => 7

Named procedures: use a variable to hold the procedure value:(define add2 (lambda (x) (+ x 2)))(add2 4) => 6(add2 9) => 11

Page 29: Functional Programming

Defining procedures

Defining a procedure: Or just use define and indicate name and parameters (define (two-times x) (+ x x)) When you define a procedure, you're really defining

a variable whose value happens to be a (pointer to a) procedure.

You can define a procedure with 0 parameters (define (foo) 15) Mind the difference (define foo 15)

Page 30: Functional Programming

Defining procedures

Variable number of arguments: Some procedures can be called at different times with

different numbers of arguments. To do this, the lambda parameter list is replaced by a single

symbol. This symbol acts as a variable that is bound to the list of the

arguments that the procedure is called on. The lambda parameter list can be:

a list of the form (x ...) a symbol a dotted pair of the form (x ... . z); in the dotted-pair case, all the

variables before the dot are bound to the corresponding arguments in the procedure call, with the single variable after the dot picking up all the remaining arguments as one list.

Page 31: Functional Programming

4. Special forms

Special forms: A kind of procedure but behaves differently Procedure calls and special forms are syntactically

similar but semantically different Examples:

set! - isn't a procedure, because its first argument is not really an expression to be evaluated in the normal way, to get a value to pass as an argument. It's the name of a place to put a value

define treats its first argument specially--the name of a variable or procedure isn't an expression that is evaluated and passed to define - it's just a name, and you're telling define to allocate some storage and use that name for it.

Page 32: Functional Programming

Special forms

Other special forms we'll see include control constructs: if, cond, and case, etc., and

logical operators and and or; forms for defining local variables: let and its

variants letrec and let*; looping constructs: named let and do; quote, which let you write complex data

structures as textual literals in your code, and lambda, which creates new procedures

Page 33: Functional Programming

5. Local variables

forms for defining local variables: let and its variants letrec and let*;

Page 34: Functional Programming

6. Control constructs

control constructs: if, cond, and case, etc., and logical operators and and or;

Page 35: Functional Programming

7. Objects and pointers

Conceptually, 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 computer and returned by the procedure

This makes things simpler

Page 36: Functional Programming

Objects and pointers

• An implementation is free to optimize away the pointers if it doesn't affect the programmer's view of things

• Most implementations actually do this

Page 37: Functional Programming

Objects and pointers

• Objects on the heap

Page 38: Functional Programming

Objects and pointers

• Reclaiming the memory

Page 39: Functional Programming

Objects and pointers

• Dymanic typing