Announcements. The current topic: Scheme. Review: BST functions. Review: Representing trees in Scheme. Reminder: Lab 2 is due on Monday at 10:30 am.

Similar documents
CS 314 Principles of Programming Languages


User-defined Functions. Conditional Expressions in Scheme

CS 61A Interpreters, Tail Calls, Macros, Streams, Iterators. Spring 2019 Guerrilla Section 5: April 20, Interpreters.

Functional Programming. Pure Functional Languages

CS 314 Principles of Programming Languages

A Brief Introduction to Scheme (II)

Functional Programming. Pure Functional Languages

Scheme Basics > (butfirst '(help!)) ()

Project 2: Scheme Interpreter

Scheme: Data. CS F331 Programming Languages CSCE A331 Programming Language Concepts Lecture Slides Monday, April 3, Glenn G.

Summer 2017 Discussion 10: July 25, Introduction. 2 Primitives and Define

Fall 2018 Discussion 8: October 24, 2018 Solutions. 1 Introduction. 2 Primitives

Functional Programming. Pure Functional Programming

CS61A Midterm 2 Review (v1.1)

Scheme: Strings Scheme: I/O

;;; Determines if e is a primitive by looking it up in the primitive environment. ;;; Define indentation and output routines for the output for

Lisp. Versions of LISP

6.184 Lecture 4. Interpretation. Tweaked by Ben Vandiver Compiled by Mike Phillips Original material by Eric Grimson

Building a system for symbolic differentiation

11/6/17. Functional programming. FP Foundations, Scheme (2) LISP Data Types. LISP Data Types. LISP Data Types. Scheme. LISP: John McCarthy 1958 MIT

Computer Science 21b (Spring Term, 2015) Structure and Interpretation of Computer Programs. Lexical addressing

Fall 2017 Discussion 7: October 25, 2017 Solutions. 1 Introduction. 2 Primitives

SCHEME 8. 1 Introduction. 2 Primitives COMPUTER SCIENCE 61A. March 23, 2017

Principles of Programming Languages Topic: Functional Programming Professor L. Thorne McCarty Spring 2003

Building a system for symbolic differentiation

6.037 Lecture 4. Interpretation. What is an interpreter? Why do we need an interpreter? Stages of an interpreter. Role of each part of the interpreter

CS 314 Principles of Programming Languages. Lecture 16

CS61A Summer 2010 George Wang, Jonathan Kotker, Seshadri Mahalingam, Eric Tzeng, Steven Tang

6.001 Notes: Section 15.1

Scheme. Functional Programming. Lambda Calculus. CSC 4101: Programming Languages 1. Textbook, Sections , 13.7

COP4020 Programming Languages. Functional Programming Prof. Robert van Engelen

Introduction to Scheme

CS115 - Module 10 - General Trees

SCHEME 7. 1 Introduction. 2 Primitives COMPUTER SCIENCE 61A. October 29, 2015

Spring 2018 Discussion 7: March 21, Introduction. 2 Primitives

Scheme: Expressions & Procedures

CS 314 Principles of Programming Languages

Scheme in Scheme: The Metacircular Evaluator Eval and Apply

Principles of Programming Languages 2017W, Functional Programming

Typed Scheme: Scheme with Static Types

Turtles All The Way Down

CSc 520 Principles of Programming Languages

SCHEME AND CALCULATOR 5b

4.2 Variations on a Scheme -- Lazy Evaluation

Syntactic Sugar: Using the Metacircular Evaluator to Implement the Language You Want

Streams, Delayed Evaluation and a Normal Order Interpreter. CS 550 Programming Languages Jeremy Johnson

Scheme Quick Reference

CS 360 Programming Languages Interpreters

CSCC24 Functional Programming Scheme Part 2

6.001 Notes: Section 8.1

Programming Languages

LECTURE 16. Functional Programming

Functional Programming. Big Picture. Design of Programming Languages

Functional Programming

CS61A Notes 02b Fake Plastic Trees. 2. (cons ((1 a) (2 o)) (3 g)) 3. (list ((1 a) (2 o)) (3 g)) 4. (append ((1 a) (2 o)) (3 g))

CS61A Discussion Notes: Week 11: The Metacircular Evaluator By Greg Krimer, with slight modifications by Phoebus Chen (using notes from Todd Segal)

CS61A Notes Disc 11: Streams Streaming Along

Functional Programming - 2. Higher Order Functions

FP Foundations, Scheme

Quicksort. Alternative Strategies for Dividing Lists. Fundamentals of Computer Science I (CS F)

Scheme Quick Reference

CSc 520. Principles of Programming Languages 7: Scheme List Processing

Fall Semester, The Metacircular Evaluator. Today we shift perspective from that of a user of computer langugaes to that of a designer of

Why do we need an interpreter? SICP Interpretation part 1. Role of each part of the interpreter. 1. Arithmetic calculator.

Introduction to Functional Programming in Racket. CS 550 Programming Languages Jeremy Johnson

CSC324 Functional Programming Efficiency Issues, Parameter Lists

Module 9: Trees. If you have not already, make sure you. Read How to Design Programs Sections 14, 15, CS 115 Module 9: Trees

CSE413 Midterm. Question Max Points Total 100

An Introduction to Scheme

CSc 520 Principles of Programming Languages. Examining Lists. Constructing Lists... 7: Scheme List Processing

Chapter 15. Functional Programming Languages

Comp 311: Sample Midterm Examination

Typed Racket: Racket with Static Types

TAIL RECURSION, SCOPE, AND PROJECT 4 11

Programming Languages

Organization of Programming Languages CS3200/5200N. Lecture 11

CSSE 304 Assignment #13 (interpreter milestone #1) Updated for Fall, 2018

CPS 506 Comparative Programming Languages. Programming Language Paradigm

Using Symbols in Expressions (1) evaluate sub-expressions... Number. ( ) machine code to add

COP4020 Programming Assignment 1 - Spring 2011

Functional programming with Common Lisp

Racket. CSE341: Programming Languages Lecture 14 Introduction to Racket. Getting started. Racket vs. Scheme. Example.

Lecture 09: Data Abstraction ++ Parsing is the process of translating a sequence of characters (a string) into an abstract syntax tree.

CS 61A Discussion 8: Scheme. March 23, 2017

1.3. Conditional expressions To express case distinctions like

CS 342 Lecture 7 Syntax Abstraction By: Hridesh Rajan

YOUR NAME PLEASE: *** SOLUTIONS ***

An Explicit-Continuation Metacircular Evaluator

CS 275 Name Final Exam Solutions December 16, 2016

From Syntactic Sugar to the Syntactic Meth Lab:

University of Massachusetts Lowell

MORE SCHEME. 1 What Would Scheme Print? COMPUTER SCIENCE MENTORS 61A. October 30 to November 3, Solution: Solutions begin on the following page.

regsim.scm ~/umb/cs450/ch5.base/ 1 11/11/13

CSE 341 Lecture 16. More Scheme: lists; helpers; let/let*; higher-order functions; lambdas

Procedural abstraction SICP Data abstractions. The universe of procedures forsqrt. Procedural abstraction example: sqrt

Discussion 4. Data Abstraction and Sequences

CIS4/681 { Articial Intelligence 2 > (insert-sort '( )) ( ) 2 More Complicated Recursion So far everything we have dened requires

CS 61A, Fall, 2002, Midterm #2, L. Rowe. 1. (10 points, 1 point each part) Consider the following five box-and-arrow diagrams.

More Scheme CS 331. Quiz. 4. What is the length of the list (()()()())? Which element does (car (cdr (x y z))) extract from the list?

Transcription:

The current topic: Scheme! Introduction! Object-oriented programming: Python Functional programming: Scheme! Introduction! Numeric operators, REPL, quotes, functions, conditionals! Function examples, helper functions, let, let*! More function examples, higher-order functions! More higher-order functions, trees Next up: More trees, lambda reductions, mutual recursion, examples, letrec Python GUI programming (Tkinter) Types and values Logic programming: Prolog Syntax and semantics Exceptions Announcements Reminder: Lab 2 is due on Monday at 10:30 am. Term Test 2 is on November 3rd in GB05. Aids allowed: Same as Term Test 1. Reminder: Deadline for Term Test 1 re-mark requests is today. 1 2 Review: Representing trees in Scheme Review: BST functions Trees are represented as lists. Each node contains its data value followed by all its children. If the "child" is a "null pointer" (that is, there is no child), it is represented by the empty list. Example: Binary trees. / \ 2 2 6 6 / 5 5 ( (2 () ()) (6 (5 () ()) ()) ) Getting the data value in a given node: > (define (key node) (car node)) > (key '( (2 () ()) (6 (5 () ()) ()) ) ) Getting the left subtree of a given node: > (define (left node) (cadr node)) > (left '( (2 () ()) (6 (5 () ()) ()) ) ) (2 () ()) Getting the right subtree of a given node: > (define (right node) (caddr node)) > (right '( (2 () ()) (6 (5 () ()) ()) ) ) (6 (5 () ()) ()) 3

Printing binary trees We want a function print-tree to do something like this: > (print-tree '( (2 () (3 () ())) (6 (5 () ()) (7 () ())))) 2 3 6 5 7 > (print-tree '( (2 () ()) (6 () ()))) 2 6 Another printing example > (print-tree (list2tree '( 2 6 8 1 7))) 2 6 1 8 7 (In all examples, we've omitted the #t that print-tree likes to finish off with.) 5 6 Printing a binary tree Environments and local variables in lambda expressions > (define (print-tree tree) (print-tree-help tree 0)) > (define (print-tree-help tree D) (cond ((null? tree)) (else (print-spaces D) (display (key tree)) (newline) (print-tree-help (left tree) (+ D 1)) (print-tree-help (right tree) (+ D 1))))) > (define (print-spaces N) (cond ((= N 0)) (else (display #\space) (display #\space) (print-spaces (- N 1))))) Recall that function definitions are equivalent to lambda expressions: > (define (mult x y) (* x y)) is equivalent to > (define mult (lambda (x y) (* x y))) Lambda expressions are a formal notation for establishing an environment (a local context) in which the lambda variables (the parameters to the function) are defined. Note that the above code doesn't completely follow functional programming style. 7 8

Environments and local variables in lambda expressions Lambda reduction Analogy: Logic expressions also establish an environment within which variables are defined. For example:!!x (P(x) Q(x)) The variable x in the above expression is a "bound" variable it has meaning only within the expression. The expression establishes the environment in which x has meaning. But the analogy isn't perfect. In a lambda expression, the variables have individual values, assigned by the caller, when the expression is evaluated. Lambda expressions get values by the process of lambda reduction: when a lambda expression is followed by a sequence of expressions, the values of those expressions are substituted for the lambda variables. ( (lambda (x y) (* x y)) 3 (+ 5))! [by lambda reduction] (* 3 9)! [by evaluation] 27 9 10 Function calls and lambda reduction let and let* are not primitive A function call in Scheme is really a lambda reduction: > (mult 3 (+ 5))! [by evaluation] ( (lambda (x y) (* x y)) 3 9)! [by lambda reduction] (* 3 9)! [by evaluation] 27 That is, we can define them in terms of other forms. (let ((v1 e1) (vn en)) expr) is equivalent to: ((lambda (v1 vn) expr) e1 en) For example: (let ((x 5) (y 3)) (* x y)) is equivalent to: ((lambda (x y) (* x y)) 5 3) 11 12

let and let* are not primitive let and let* are not primitive Similarly: (let* ((v1 e1) (v2 e2)) expr) is equivalent to: ((lambda (v1) ((lambda (v2) expr) e2)) e1) For example: (let* ((x 5) (y (* x 2))) (+ x y)) is equivalent to: ((lambda (x) ((lambda (y) (+ x y)) (* x 2))) 5) Tracing the previous example: ((lambda (x) ((lambda (y) (+ x y)) (* x 2))) 5)! [by lambda reduction] ((lambda (y) (+ 5 y)) (* 5 2))! [by evaluation] ((lambda (y) (+ 5 y)) 10)! [by lambda reduction] (+ 5 10)! [by evaluation] 15 All binding of values to variables in let and let* is by parameter passing (that is, lambda reduction), not by assignment! 13 1 What cons really does What cons really does We've been treating cons as a function that "appends" to the beginning of a "list". This is the right general idea. But it leaves out details about what's happening "behind the scenes". Some of you have (accidentally?) noticed what happens when the second argument given to cons is not a list: > (cons 'a 'b) (a. b) > (cons 1 2) (1. 2) List are implemented as linked lists. Each node has two parts. A part storing (pointing to) data. This is the node's car. A part that's meant to store a pointer to the next node. This is the node's cdr. Think of this as the node's "next" pointer. cons creates a linked list node (also known as a pair). The first argument to cons is stored in the new node's car part. The second argument to cons is stored in the new node's cdr part. e.g. (cons 'a '()) produces: Notice that the return values include a dot. a 15 16

Displaying lists To display (output) a list, Scheme traverses the list's linked list, printing each node's car part. For example, the following list is displayed as (a b c). (cons 'a 'b) produces: Displaying lists a b a b c Observe that a properly-formed list ends with a null pointer. Another example: the nested list (a (b d) c) is stored as: When traversing this list, Scheme finds that the node's cdr part doesn't point to the next node, but instead points to a symbol. This list is displayed as (a. b) This list's cdr is the atom b, not the list (b). The list (a b) produced by (cons 'a '(b)) is stored as: a c b d a b 17 18 Mutual recursion map-even and map-odd Mutual recursion is a form of recursion where two functions call each other (rather than themselves). Functions f1 and f2 are mutually recursive if f1 calls f2 and f2 calls f1. Let's define variants of map that only apply the given function to certain parts of the given list (and leave other parts unchanged). map-even takes a function f and a list L, and returns a new list in which each even-positioned element is the result of applying f to the corresponding element in L, and each odd-positioned element is simply the corresponding element in L unchanged. map-odd takes a function f and a list L, and returns a new list in which each odd-positioned element is the result of applying f to the corresponding element in L, and each even-positioned element is simply the corresponding element in L unchanged. : > (map-even car '((1 2 3) ( 5 6) (7 8) (a b c))) ((1 2 3) (7 8) a) > (map-odd car '((1 2 3) ( 5 6) (7 8) (a b c))) (1 ( 5 6) 7 (a b c)) > (map-even (lambda (x) (* 2 x)) '(1 1 1 3 3 3)) (1 2 1 6 3 6) > (map-odd (lambda (x) (* 2 x)) '(1 1 1 3 3 3)) (2 1 2 3 6 3) 19 20

map-even and map-odd We'll define map-even and map-odd so that they're mutually recursive: > (define (map-odd f L) (cond ((null? L) ()) (else (cons (f (car L)) (map-even f (cdr L)))) )) > (define (map-even f L) (cond ((null? L) ()) (else (cons (car L) (map-odd f (cdr L)))) )) map-even and map-odd Call: (map-even car '((a b) (c d) (1 2) (3 ))) Trace: (map-even car '((a b) (c d) (1 2) (3 ))) (map-odd car '((c d) (1 2) (3 ))) (map-even car '((1 2) (3 ))) (map-odd car '((3 ))) (map-even car '()) () (3) ((1 2) 3) (c (1 2) 3) ((a b) c (1 2) 3) 21 22 Write a function maketester that takes two unary predicates f1 and f2 (a predicate is a function that returns true or false), and returns a function that takes a list and returns true iff all odd-positioned elements satisfy f1 and all even-positioned elements satisfy f2. For example: > ((maketester list? symbol?) '((a b) a (c) d)) #t > ((maketester symbol? number?) '(a 1 2 a)) #f Defining maketester, first solution: > (define (maketester f1 f2) (lambda (L) ((f1 (car L)) ((maketester f2 f1) (cdr L))) ))) This works, but notice that the function that's returned by maketester calls maketester each time it's called. Let's modify maketester so the returned function does not call maketester. 23 2

Defining maketester, second solution (using map-odd and mapeven): > (define (maketester f1 f2) (lambda (L) (eval (cons 'and (map-even f2 (map-odd f1 L)))) )) Observe we use map-odd to check if the odd-positioned elements satisfy f1, we use map-even to check if the even-positioned elements satisfy f2, and we use and to combine all the results. Now let's try to define maketester using mutually recursive lambda expressions. > (define (maketester f1 f2) (let ((test-odd (lambda (L) ((f1 (car L)) (test-even (cdr L))) ))) (test-even (lambda (L) ((f2 (car L)) (test-odd (cdr L))) )))) test-odd)) 25 26 letrec General idea: test-odd checks if odd-positioned elements satisfy f1. test-even checks if even-positioned elements satisfy f2. test-odd and test-even take turns doing the checking. This is accomplished using mutual recursion. But the code doesn't work: > ((maketester symbol? number?) '(a 1 2 a)) reference to undefined identifier: test-even What's going on? The definition of test-odd refers to test-even, but we're using let, so the name test-even doesn't "exist" within the definition of test-odd. Using let* instead of let won't solve the problem, since then test-odd exists within the definition of test-even, but test-even still doesn't exist within the definition of test-odd. Solution: Use letrec, which allows lambda expressions to refer to each other (which allows for mutual recursion). > (define (maketester f1 f2) (letrec ((test-odd (lambda (L) ((f1 (car L)) (test-even (cdr L))) ))) (test-even (lambda (L) ((f2 (car L)) (test-odd (cdr L))) )))) test-odd)) 27 28

Write a function findsequence that takes two unary predicates f1 and f2, and returns a function that takes a list and returns the leftmost pair of adjacent elements in the list such that the first element of the pair satisfies f1 and the second element satisfies f2, if such a pair exists, and returns #f otherwise. For example: > ((findsequence list? symbol?) '(1 (a b) a (c) d)) ((a b) a) > ((findsequence symbol? number?) '((z) 1 a 3 2 a)) (a 3) > ((findsequence symbol? number?) '((z) 1 a (d) 2 3)) #f Defining findsequence: > (define (findsequence f1 f2) (letrec ((g (lambda (L) (cond ((null? L) #f) ((null? (cdr L)) #f) ((and (f1 (car L)) (f2 (cadr L))) (list (car L) (cadr L))) (else (g (cdr L))) )))) g)) Observe that letrec is needed here, since otherwise function g won't be able to call itself (since the name g won't exist within its own definition). 29 30 Exercises More exercises Fix print-tree (defined in this lecture) so that it's clear from the output whether an only child is a right-child or a left-child. Hint: Do something special when the left child is null but the right child is not null. Write a function map-odd-even that takes functions f1 and f2, and a list L, and returns a new list in which each odd-positioned element is the result of applying f1 to the corresponding element in L, and each evenpositioned element is the result of applying f2 to the corresponding element in L. Do not define any helper functions, and do not use map-odd or map-even. : > (map-odd-even car cdr '((a b) (1 2) (#t #f) (3) ( 5))) (a (2) #t () ) Write a function make-odd-even that takes functions f1 and f2, and returns a function that takes a list returns a new list in which each oddpositioned element is the result of applying f1 to the corresponding element in L, and each even-positioned element is the result of applying f2 to the corresponding element in L. Do not use any helper functions. Instead, use letrec and mutually recursive lambda expressions. : > ((make-odd-even car cdr) '((a b) (1 2) (#t #f) (3) ( 5))) (a (2) #t () ) > ((make-odd-even list? symbol?) '((a b) (a b) c d (e) f))) (#t #f #f #t #t #t) > (map-odd-even list? symbol? '((a b) (a b) c d (e) f))) (#t #f #f #t #t #t) 31 32