
Historical Perspective I Second oldest programming language after Fortran CS345H: Programming Languages I Developed in late 1950’s at MIT by John McCarthy Lecture: LISP I Original purpose: to facilitate research in artificial intelligence I In research, one may not initially know solution to problem; Thomas Dillig thus, development of program and research hand-in-hand I Thus, program may need to be changed radically as a result of experimental evaluation: exploratory programming I LISP is popular for exploratory programming Thomas Dillig, CS345H: Programming Languages Lecture: LISP 1/30 Thomas Dillig, CS345H: Programming Languages Lecture: LISP 2/30 LISP, Lists, and Dialects Overview Of Important Ideas in LISP I The main data structures in LISP are lists I Functional, expression-based language I LISP is named after its main data structure: LISt Processor I Heavily influenced by lambda calculus I Another feature of LISP: need to write lots of parentheses! I First language to allow recursive and higher-order functions I Students who hate parentheses in LISP have given it many nicknames: I Lists are fundamental data type I ”Lost In Stupid Parentheses” I ”Programs as data:” programs and data represented same way I ”Lots of Irritating Superfluous Parentheses” I Dynamic scoping (in original LISP) I Today, there are many variations of the original LISP: I First language that has garbage collection Common LISP, Scheme, Clojure Thomas Dillig, CS345H: Programming Languages Lecture: LISP 3/30 Thomas Dillig, CS345H: Programming Languages Lecture: LISP 4/30 LISP as a Functional Language LISP and Lambda Calculus I Just like L and λ-calculus, Lisp also has lambda expressions! I LISP is a functional programming language I This is how you write a function that adds 1 to its argument: I Characteristic of functional languages (lambda (x) (+ x 1)) 1. No state or mutable data I In LISP, must write + x 1 instead of x+1 because all 2. No statements (such as assignment), only expressions! operations are in prefix form (to make parsing easier!) 3. Expressions have no side-effects I This is how you write application expressions in LISP: ((lambda (x) (+ x 1)) 3) I You are already very familiar with a functional language:L! I Evaluates to 4 I All functional languages have their roots in lambda calculus I Don’t forget any of the parentheses – otherwise, won’t work! Thomas Dillig, CS345H: Programming Languages Lecture: LISP 5/30 Thomas Dillig, CS345H: Programming Languages Lecture: LISP 6/30 1 Higher-Order Functions Named vs. Anonymous Functions I Just like L and λ-calculus, very easy to write higher-order I Lambda expressions such as (lambda (x) (+ x 1)) are functions in LISP anonymous functions (i.e., functions without a name) I A higher-order function is one that takes other functions as I Like L, LISP also allows giving functions a name input or returns a function I This is how you name functions in LISP: I Here is higher-order function in LISP for composing two functions: (define compose (lambda (f g) ((lambda (x) (f(g x))))) (lambda (f g) ( (lambda (x) (f(g x))))) I You can call named functions like this: I This function takes as input two function f and g and another (compose (lambda (x) (+x x)) (lambda (x) (* x x))) argument x and computes f(g(x)) Thomas Dillig, CS345H: Programming Languages Lecture: LISP 7/30 Thomas Dillig, CS345H: Programming Languages Lecture: LISP 8/30 Named Functions and Recursion Named Functions and Recursion (define f (lambda (x) I As we saw in L, named functions make recursion more natural (cond ((eq x 0) 0) (true + x f(- x 1)))) I Here is a recursive function in LISP: (define f (lambda (x) I The expression (eq e1 e2) evaluates to true if e1 and e2 (cond ((eq x 0) 0) (true + x f(- x 1)))) are equal, and to false otherwise I So, what does the recursive function above compute? I This function uses a conditional expression: (cond (p1 e1) ... (pn en)) I Recall: possible to encode recursion without named functions I Here, we evaluate each condition p in order from left-to-right I McCarthy’s original paper on LISP remarks that lambda expressions are not sufficient for writing recursive functions I If pi is the first expression that evaluates to true, then we evaluate corresponding expression ei I Apparently, Y-combinator not known to McCarthy and his group back then – you know better! Thomas Dillig, CS345H: Programming Languages Lecture: LISP 9/30 Thomas Dillig, CS345H: Programming Languages Lecture: LISP 10/30 Atoms and Lists List Operators I Two fundamental data types in LISP: atoms and lists I List operations in LISP are: cons car cdr I Atoms are integers, floating point numbers and symbolic values, such as x I cons appends two lists or atoms together I Lists in LISP are singly-linked lists; each cell in list called cons I car,cdr take lists apart: car gives first elem,cdr gives rest I A cons consists of two pointers, called car and cdr I nil denotes empty list I Can think of car as data stored in current list cell and cdr is I Example: (cons 1 2 (cons 3 4)) evaluates to (1 2 (3 4)) a pointer to the rest of the list I Example:(cons 1 2 (cdr (cons 3 4))) evaluates to (1 2 3) Thomas Dillig, CS345H: Programming Languages Lecture: LISP 11/30 Thomas Dillig, CS345H: Programming Languages Lecture: LISP 12/30 2 Programs as Data Dynamic vs. Static Scoping I In LISP, programs and data have the same internal representation. I The original version of LISP was dynamically scoped I Can write LISP programs that build data structures representing other LISP programs and evaluate them! I Modern LISP dialects are statically scoped (e.g., Scheme) I There is a built-in eval function that calls the Lisp interpreter I Statically scoped languages use the textually closest definition from the Lisp interpreter of a variable (source-code based) I Example: Suppose we have read function that reads input I Dynamically scoped languages use the most recent run-time from user definition of a variable (run-time notion) I (eval (read)) executes LISP program source code entered by user! Thomas Dillig, CS345H: Programming Languages Lecture: LISP 13/30 Thomas Dillig, CS345H: Programming Languages Lecture: LISP 14/30 Dynamic vs. Static Scoping Example Garbage Collection I Consider the following program: I LISP is the first programming language that had the idea of (define h (lambda (a) (+ a 1))) garbage collection (define g (lambda (z) ( + (h 0) z)) (define f (lambda (y) ( I A memory location is garbage if it can no longer be accessed (define h (lambda (a) (+ a 2))) by the program (g y)))) I If a memory location is garbage, changing the value stored in (f 3) that location cannot change the result of the program I In statically-scoped dialect of LISP, what does this program I Thus, if we had a way of finding all memory locations that are evaluate to? 4 garbage, we could reclaim those memory locations and use them for some other purpose I In dynamically-scoped LISP, what does this program evaluate to? 5 Thomas Dillig, CS345H: Programming Languages Lecture: LISP 15/30 Thomas Dillig, CS345H: Programming Languages Lecture: LISP 16/30 Explicit vs. Automatic Memory Management Advantages of Garbage Collection I Garbage collection is the task of detecting garbage during the I Garbage collection makes programming much easier! execution of a program and reclaiming this unused memory I In explicitly-memory managed languages, programmer must I Operating system keeps a list of available memory called the track which memory locations are unused free list I Explicit memory management constant source of headaches: I In languages that are not garbage-collected (e.g., C) programmer must explicitly call free to deallocate an unused I Memory leaks: forgetting to delete unused memory) memory location I Dangling pointers: deleting memory that’s still in use I In garbage-collected languages like LISP and Java, the programmer does not need to worry about deallocating I In automatically memory-managed languages like LISP and memory – this is done automatically by the run-time system Java, such errors are not possible! Thomas Dillig, CS345H: Programming Languages Lecture: LISP 17/30 Thomas Dillig, CS345H: Programming Languages Lecture: LISP 18/30 3 Disadvantages of Garbage Collection How Does Garbage Collection Work? I In past few decades, lots of research on garbage collection I Potential disadvantage of garbage collection is overhead I Original LISP garbage collector used simple algorithm called I In automatically garbage-collected languages, we must do Mark-and-Sweep work at run-time to figure out what is garbage I In Mark-and-Sweep, we reserve a bit for each memory cell, I Identifying what is garbage and reclaiming it takes time; thus, called tag bit, to identify whether it is accessible there is a performance penalty I If tag bit is 1, means cell is in use; if it is 0, it’s unused I While the garbage collector is running, program can feel sluggish, unresponsive I Mark-and-Sweep has two phases, called mark and sweep I But for many programmers, this is a small price to pay for I In mark phase, garbage collector sets tag bits inconvenience of manually managing memory I In sweep phase, garbage collector reclaims cells with tag bit 0 Thomas Dillig, CS345H: Programming Languages Lecture: LISP 19/30 Thomas Dillig, CS345H: Programming Languages Lecture: LISP 20/30 Mark-and-Sweep Stop the World Collectors I Mark-and-sweep is easy to understand, easy to implement I When memory is low, garbage collector initializes tag bits of all memory cells to 0 I But it stops the world: while garbage collector is
Details
-
File Typepdf
-
Upload Time-
-
Content LanguagesEnglish
-
Upload UserAnonymous/Not logged-in
-
File Pages5 Page
-
File Size-