CS1102: Macros and Recursion

Similar documents
CS1102: Adding Error Checking to Macros

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

RACKET BASICS, ORDER OF EVALUATION, RECURSION 1

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

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

Repetition Through Recursion

SCHEME The Scheme Interpreter. 2 Primitives COMPUTER SCIENCE 61A. October 29th, 2012

CS 370 The Pseudocode Programming Process D R. M I C H A E L J. R E A L E F A L L

Macros & Streams Spring 2018 Discussion 9: April 11, Macros

Intro. Scheme Basics. scm> 5 5. scm>

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

Functional Programming - 2. Higher Order Functions

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

CSCC24 Functional Programming Scheme Part 2

Lecture 11: Testing and Design Statistical Computing, Wednesday October 21, 2015

MetacircularScheme! (a variant of lisp)

CS 342 Lecture 7 Syntax Abstraction By: Hridesh Rajan

Functional abstraction. What is abstraction? Eating apples. Readings: HtDP, sections Language level: Intermediate Student With Lambda

Functional abstraction

CS115 - Module 10 - General Trees

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

An Explicit Continuation Evaluator for Scheme

(Provisional) Lecture 08: List recursion and recursive diagrams 10:00 AM, Sep 22, 2017

CS1102: What is a Programming Language?

SCHEME AND CALCULATOR 5b

Racket: Macros. Advanced Functional Programming. Jean-Noël Monette. November 2013

CS 320: Concepts of Programming Languages

CS 331: Artificial Intelligence Informed Search. Informed Search

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

COMP 161 Lecture Notes 16 Analyzing Search and Sort

CS 135 Winter 2018 Tutorial 7: Accumulative Recursion and Binary Trees. CS 135 Winter 2018 Tutorial 7: Accumulative Recursion and Binary Trees 1

CS1 Lecture 5 Jan. 26, 2018

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

Lecture 6: Sequential Sorting

The listproc package

Decision Making and Loops

Lists. Readings: HtDP, sections 9 and 10. Avoid 10.3 (uses draw.ss). CS 135 Winter : Lists 1

Lecture #23: Conversion and Type Inference

An introduction to Scheme

Outline. Data Definitions and Templates Syntax and Semantics Defensive Programming

The second statement selects character number 1 from and assigns it to.

Conversion vs. Subtyping. Lecture #23: Conversion and Type Inference. Integer Conversions. Conversions: Implicit vs. Explicit. Object x = "Hello";

Lecture 19 CSE August You taught me Language, and my profit on t is I know how to curse. William Shakspere, The Tempest, I, ii.

CS 314 Principles of Programming Languages. Lecture 16

Lecture #13: Type Inference and Unification. Typing In the Language ML. Type Inference. Doing Type Inference

CS 331: Artificial Intelligence Informed Search. Informed Search

Concepts of programming languages

Lecture 8: Iterators and More Mutation

STATS 507 Data Analysis in Python. Lecture 2: Functions, Conditionals, Recursion and Iteration

Lecture 2: SML Basics

Working with recursion. From definition to template. Readings: HtDP, sections 11, 12, 13 (Intermezzo 2).

Working with recursion

Lecture 5: Implementing Lists, Version 1

Discussion 12 The MCE (solutions)

This lecture covers: Prolog s execution strategy explained more precisely. Revision of the elementary Prolog data types

CSE 413 Languages & Implementation. Hal Perkins Winter 2019 Structs, Implementing Languages (credits: Dan Grossman, CSE 341)

More About Recursive Data Types

6.001 Notes: Section 4.1

Introduction to Typed Racket. The plan: Racket Crash Course Typed Racket and PL Racket Differences with the text Some PL Racket Examples

61A LECTURE 22 TAIL CALLS, ITERATORS. Steven Tang and Eric Tzeng July 30, 2013

CS152: Programming Languages. Lecture 7 Lambda Calculus. Dan Grossman Spring 2011

Lecture 4 CSE July 1992

Solving Your Problem by Generalization

Induction and Semantics in Dafny

YOUR NAME PLEASE: *** SOLUTIONS ***

General Syntax. Operators. Variables. Arithmetic. Comparison. Assignment. Boolean. Types. Syntax int i; float j = 1.35; int k = (int) j;

User-defined Functions. Conditional Expressions in Scheme

CS103 Handout 29 Winter 2018 February 9, 2018 Inductive Proofwriting Checklist

Delayed Expressions Fall 2017 Discussion 9: November 8, Iterables and Iterators. For Loops. Other Iterable Uses

Input, output, and sequence

Module 5: Lists. Readings: HtDP, Sections 9, 10.

CS 1101 Exam 3 A-Term 2013

An Introduction to Functions

C++: Overview and Features

Understanding Recursion

CS113: Lecture 4. Topics: Functions. Function Activation Records

ormap, andmap, and filter

Functional Programming. Pure Functional Languages

CSE413: Programming Languages and Implementation Racket structs Implementing languages with interpreters Implementing closures

6.001 Recitation 23: Register Machines and Stack Frames

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

Recursively Enumerable Languages, Turing Machines, and Decidability

Trees. Example: Binary expression trees. Example: Evolution trees. Readings: HtDP, sections 14, 15, 16.

(Provisional) Lecture 32: Estimated Value, Minimax, Functional Data 10:00 AM, Nov 20, 2017

Functional Programming. Pure Functional Languages

Chapter 7. Iteration. 7.1 Multiple assignment

Lecture 15 Binary Search Trees

Extra Lecture #7: Defining Syntax

Racket Style Guide Fall 2017

Scheme Quick Reference

1 Dynamic Programming

A Brief Introduction to Scheme (II)

An Introduction to Python

Variables. Substitution

CS1 Recitation. Week 2

CSCI-1200 Data Structures Fall 2017 Lecture 10 Vector Iterators & Linked Lists

Functional Programming. Pure Functional Programming

Racket Pattern Matching

Project 5 - The Meta-Circular Evaluator

Persistent Data Structures

Transcription:

CS1102: Macros and Recursion Kathi Fisler, WPI October 5, 2009 This lecture looks at several more macro examples. It aims to show you when you can use recursion safely with macros and when you can t. 1 Multi-Argument Or We talked about how to define or as a macro, and why it needed to be defined as a macro instead of as a function. As a reminder, we developed the following macro for or (calling it myor to avoid a name clash within Scheme): [(myor e1 e2) [else e2])])) This macro limited or to two arguments. The real or macro in Scheme accepts arbitrary numbers of arguments. Here are some examples: > (or (= 3 2)) false > (or (= 3 4) (> 6 9) (< 2 7)) true Let s change myor to accept an arbitrary number of arguments. How might we write that? First, we need to change the input pattern to expect an arbitrary number of arguments. Then, if e1 isn t true, check myor on the rest of the inputs: [(myor e1... ) [else (myor... )])])) Scheme rejects this with an error saying syntax: missing ellipses with pattern variable in template in: e1. The problem is in the else clause: you can t have... without the variable that goes with it 1

being nearby. We don t want to insert e1 into the myor in the else clause, so we need to introduce a second pattern variable: [(myor e1 e2... ) [else (myor e2... )])])) Trying this on input (myor (= 2 2) (> 3 4)) yields an error myor: bad syntax in: (myor). What happened? Let s look at the sequence of expansions that Scheme performs to expand uses of myor according to the pattern: (myor (= 2 2) (> 3 4)) = (cond [(= 2 2) true] [else (myor (> 3 4))]) = (cond [(= 2 2) true] [else (cond [(> 3 4) true] [else (myor)])]) = error Notice that the second else clause needs to expand (myor), but the input pattern requires at least one argument (e1). To handle this, add another pattern to the macro that defines myor with no arguments. then we need to adjust the output pattern. How about the following? [(myor) false] [(myor e1 e2... ) [else (myor e2... )])])) The first pattern is like the base case in a recursive function it gives a concrete answer on a specific number of arguments. The second is the recursive case. As in the recursions we ve written before, we reduce the number of arguments on the recursive call. 2 Real For-loops A friend is fed-up with the lack of for and while loops in Scheme and decides to implement his own for-loop construct. As an example, your friend wants to be able to type (for i 0 5 (printf " a " i)) 2

and have Scheme produce 0 1 2 3 4 5 (with void returned as the result of the expression). Should you implement for as a function or a macro? Why? For looks like a macro because of the expression you want to iterate over. If you implement for as a function, you ll run the printf when you call for, and you ll get an unbound identifier error because you have no value for i. With that in mind, write a macro for for. (loop (+ 1 var)))]))] Notice that this for-loop does not use assignment (as you are accustomed to using with forloops). There s no need to assign an index variable you can just use recursion. Isn t this limiting though, because the macro fixes how much to increase i by each time? We could relax that by adding another pattern to the macro that supplies that information: (loop (+ 1 var)))]))] (loop low))] [(for var low high expr incr) (loop (+ var incr))])))] Note that this macro duplicates a lot of code across the two cases. We can fix that by converting the case with no increment supplied into the case with an increment supplied. (for var low high expr 1)] [(for var low high expr incr) 3

(loop (+ var incr)))]))] But wait! This looks recursive, like what we had tried for the multi-armed or. Why does this one work, when the recursive or did not? This macro isn t recursive. The first version rewrites into the second one time only. The recursion is in the loop function, which does not use for again. In the case of or, the recursion invoked the macro itself; that created the infinite loop. As an aside, you may have wondered why we didn t try to break up the for macro into two cases as we did for the multi-armed or. For that, you might have tried the following: [(for var low var expr) expr] (begin expr (for var low (+ 1 var)))])) This isn t a valid macro, since the first cases tries to use var twice and Scheme doesn t support that. You can t split up these cases in this manner. 3 Map Since we ve written a recursive macro for or, why don t we write one for map? How about this? (define-syntax mymap [(mymap func lst) (cond [(empty? lst) empty] [(cons? lst) (cons (func (first lst)) (mymap func (rest lst)))])])) If we test this macro, we find we go into an infinite loop. Why? Recursion worked for or, so why doesn t it work for map? There s a big difference between the two macros. With myor, notice that the recursion has a base case as one of the patterns in the macro. In mymap, there s only one case. Macro-expansion works by replacing every use of a macro with its output pattern until no more uses of macros remain. Furthermore, since macro-expansion takes place without evaluating expressions (the whole point of having them!), there s no way to hit a base case within the expanded code. In other words, macro-expansion of a call to mymap proceeds in several steps, ad infinitum: (mymap square (list 1 2 3)) = (cond [(empty? (list 1 2 3)) empty] 4

[(cons? (list 1 2 3)) (cons (square (first (list 1 2 3))) (mymap square (rest (list 1 2 3))))]) = (cond [(empty? (list 1 2 3)) empty] [(cons? (list 1 2 3)) (cons (square (first (list 1 2 3))) (cond [(empty? (rest (list 1 2 3))) empty] [(cons? (rest (list 1 2 3))) (cons (square (first (rest (list 1 2 3)))) (mymap square (rest (rest (list 1 2 3)))))]))]) =... Without evaluating the lists, there s no way to stop the expansion, hence the infinite loop. 4 Summary Macros can be recursive, but the base case must be one of the (multiple) patterns, not buried within one of the output patterns. This is necessary for macro expansion to terminate. 5