Pattern Matching for Scheme

Similar documents
exp ::= (match exp clause :::) j clause :::) j * clause :::) j (match-let ([pat exp] :::) body) j (match-let* ([pat exp] :::) body) j (match-letrec ([

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

User-defined Functions. Conditional Expressions in Scheme

Essentials of Programming Languages Language

Essentials of Programming Languages Language

Notes on Higher Order Programming in Scheme. by Alexander Stepanov

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

Introduction to Scheme

Scheme Quick Reference

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

Functional Programming. Pure Functional Programming

The Typed Racket Guide

Scheme Quick Reference

Documentation for LISP in BASIC

MIT Scheme Reference Manual

An Introduction to Scheme

Typed Racket: Racket with Static Types

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

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

Functional Programming. Pure Functional Languages

Title. Authors. Status. 1. Abstract. 2. Rationale. 3. Specification. R6RS Syntax-Case Macros. Kent Dybvig

COP4020 Programming Assignment 1 - Spring 2011

CSE 341 Section 7. Ethan Shea Autumn Adapted from slides by Nicholas Shahan, Dan Grossman, Tam Dang, and Eric Mullen

INTRODUCTION TO SCHEME

Below are example solutions for each of the questions. These are not the only possible answers, but they are the most common ones.

CSE 413 Midterm, May 6, 2011 Sample Solution Page 1 of 8

Functional Programming. Pure Functional Languages

CSE 341 Section 7. Eric Mullen Spring Adapted from slides by Nicholas Shahan, Dan Grossman, and Tam Dang

Programming Languages

Programming Languages

Scheme Tutorial. Introduction. The Structure of Scheme Programs. Syntax

CS 314 Principles of Programming Languages

A Brief Introduction to Scheme (II)

Revised 5 Report on the Algorithmic Language Scheme

Evaluating Scheme Expressions

How to Design Programs Languages

Project 2: Scheme Interpreter

COP4020 Programming Languages. Functional Programming Prof. Robert van Engelen

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

An Explicit Continuation Evaluator for Scheme

Typed Scheme: Scheme with Static Types

6.034 Artificial Intelligence February 9, 2007 Recitation # 1. (b) Draw the tree structure corresponding to the following list.

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

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

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

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

CS 360 Programming Languages Interpreters

CS 314 Principles of Programming Languages

CS 342 Lecture 7 Syntax Abstraction By: Hridesh Rajan

LECTURE 16. Functional Programming

Overview. CS301 Session 3. Problem set 1. Thinking recursively

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

Building a system for symbolic differentiation

Kent Dybvig, Will Clinger, Matthew Flatt, Mike Sperber, and Anton van Straaten

Deferred operations. Continuations Structure and Interpretation of Computer Programs. Tail recursion in action.

Functional Programming Languages (FPL)

CS 314 Principles of Programming Languages. Lecture 16

Project 5 - The Meta-Circular Evaluator

Scheme in Scheme: The Metacircular Evaluator Eval and Apply

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

The Typed Racket Guide

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

CS 314 Principles of Programming Languages

CS 275 Name Final Exam Solutions December 16, 2016

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

Scheme: Strings Scheme: I/O

Comp 311: Sample Midterm Examination

Principles of Programming Languages COMP251: Functional Programming in Scheme (and LISP)

CSc 520 Principles of Programming Languages

Concepts of programming languages

Principles of Programming Languages 2017W, Functional Programming

Racket: Modules, Contracts, Languages

The Typed Racket Reference

JRM s Syntax-rules Primer for the Merely Eccentric

Vectors in Scheme. Data Structures in Scheme

Functional Languages. Hwansoo Han

Symbolic Programming. Dr. Zoran Duric () Symbolic Programming 1/ 89 August 28, / 89

SMURF Language Reference Manual Serial MUsic Represented as Functions

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

CSC 533: Programming Languages. Spring 2015

Syntax: Meta-Programming Helpers

Control in Sequential Languages

Fundamentals of Artificial Intelligence COMP221: Functional Programming in Scheme (and LISP)

Box-and-arrow Diagrams

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

CSE341: Programming Languages Lecture 17 Implementing Languages Including Closures. Dan Grossman Autumn 2018

Parser Tools: lex and yacc-style Parsing

Redex: Practical Semantics Engineering

Building a system for symbolic differentiation

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

Lecture08: Scope and Lexical Address

Building up a language SICP Variations on a Scheme. Meval. The Core Evaluator. Eval. Apply. 2. syntax procedures. 1.

Functional Programming

C311 Lab #3 Representation Independence: Representation Independent Interpreters

CS 342 Lecture 8 Data Abstraction By: Hridesh Rajan

Data Abstraction. An Abstraction for Inductive Data Types. Philip W. L. Fong.

FP Foundations, Scheme

CS 480. Lisp J. Kosecka George Mason University. Lisp Slides

Functional Languages. CSE 307 Principles of Programming Languages Stony Brook University

The role of semantic analysis in a compiler

Transcription:

Pattern Matching for Scheme Andrew K. Wright March 1996 Department of Computer Science MS 132 Rice University 6100 Main Street Houston, Texas 77005-1892

Contents 1 Match 1 1.1 Definition... 1 1.1.1 Patterns... 3 1.1.2 MatchFailure... 4 1.2 CodeGeneration... 4 1.3 Examples... 5 i

CONTENTS CONTENTS ii

1. Match 1.1 Definition The complete syntax of the pattern matching expressions follows: exp ::= (match exp clause...) clause...) * clause...) (match-let ([pat exp]...) body) (match-let* ([pat exp]...) body) (match-letrec ([pat exp]...) body) (match-let var ([pat exp]...) body) (match-define pat exp) clause ::= [pat body] [pat (=> identifier) body] Figure 1.1 gives the full syntax for patterns. The next subsection describes the various patterns. The match-lambda and match-lambda* forms are convenient combinations of match and lambda, and can be explained as follows: [pat body]...) = (lambda (x) (match x [pat body]...)) * [pat body]...) = (lambda x (match x [pat body]...)) where x is a unique variable. The match-lambda form is convenient when defining a single argument function that immediatelydestructures its argument. The match-lambda* form constructs a function that accepts anynumber of arguments; the patterns of match-lambda* should be lists. The match-let, match-let*, match-letrec, andmatch-define forms generalize Scheme s let, let*, letrec, and define expressions to allow patterns in the binding position rather than just variables. For example, the following expression: (match-let ([(x y z) (list 1 23)]) $body$) binds x to 1, y to 2, andz to 3 in body. These forms are convenient for destructuring the result of a function that returns multiple values. As usual for letrec and define, pattern variables bound by match-letrec and match-define should not be used in computing the bound value. The match, match-lambda, andmatch-lambda* forms allow the optional syntax (=> identifier) between the pattern and the bodyof a clause. When the pattern match for such a clause succeeds, the identifier is bound to a failure procedure of zero arguments within the body. If this procedure is invoked, it jumps back to the pattern matching expression, and resumes the matching process as if the pattern had failed to match. The body must not mutate the object being matched, otherwise unpredictable behavior may result. 1

1.1. Definition 1. Match Pattern : Matches : pat ::= identifier anything, and binds identifier as a variable anything () itself (the emptylist) #t itself #f itself string an equal? string number an equal? number character an equal? character s-expression an equal? s-expression symbol an equal? symbol (special case of s-expression) (pat 1...pat n ) a proper list of n elements (pat 1...pat n. pat n+1 ) a list of n or more elements (pat 1...pat n pat n+1...) a proper list of n or more elements 1 (pat 1...pat n pat n+1..k) a proper list of n + k or more elements #(pat 1...pat n ) a vector of n elements #&pat abox ($ struct pat 1...pat n ) a structure (and pat 1...pat n ) if all of pat 1 through pat n match (or pat 1...pat n ) any if of pat 1 through pat n match (not pat 1...pat n ) if none of pat 1 through pat n match (? predicate pat 1...pat n ) if predicate true and pat 1 through pat n all match (set! identifier) anything, and binds identifier as a setter (get! identifier) anything, and binds identifier as a getter qp a quasipattern Quasipattern: Matches : qp ::= () itself (the emptylist) #t itself #f itself string an equal? string number an equal? number character an equal? character identifier an equal? symbol (qp 1...qp n ) a proper list of n elements (qp 1...qp n. qp n+1 ) a list of n or more elements (qp 1...qp n qp n+1...) a proper list of n or more elements (qp 1...qp n qp n+1..k) a proper list of n + k or more elements #(qp 1...qp n ) a vector of n elements #&qp abox,pat a pattern,@pat a pattern, spliced Figure 1.1: Pattern Syntax 2

1. Match 1.1. Definition 1.1.1 Patterns Figure 1.1 gives the full syntax for patterns. Explanations of these patterns follow. identifier (excluding the reserved names?, $,, and, or, not, set!, get!,..., and..k for non-negative integers k): matches anything, and binds a variable of this name to the matching value in the body. : matches anything, without binding any variables. (), #t, #f, string, number, character, s-expression: These constant patterns match themselves, ie., the corresponding value must be equal? to the pattern. (pat 1...pat n ): matches a proper list of n elements that match pat 1 through pat n. (pat 1...pat n.pat n+1 ): matches a (possiblyimproper) list of at least n elements that ends in something matching pat n+1. (pat 1...pat n pat n+1...): matches a proper list of n or more elements, where each element of the tail matches pat n+1. Each pattern variable in pat n+1 is bound to a list of the matching values. For example, the expression: (match (let ([x 1][y 2]) z) [( let ((binding values)...) exp) body]) binds binding to the list (x y), values to the list (1 2), and expto z in the bodyof the matchexpression. For the special case where pat n+1 is a pattern variable, the list bound to that variable may share with the matched value. (pat 1...pat n pat n+1..k): This pattern is similar to the previous pattern, but the tail must be at least k elements long. The pattern keywords..0 and... are equivalent. #(pat 1...pat n ): matches a vector of length n, whose elements match pat 1 through pat n. #&pat: matches a box containing something matching pat. matches a structure declared with define-structure or define-const- ($ struct pat 1...pat n ): structure. (and pat 1...pat n ): matches if all of the subpatterns match. This pattern is often used as (and xpat) to bind x to to the entire value that matches pat (cf. as-patterns in ML or Haskell). (or pat 1...pat n ): matches if anyof the subpatterns match. At least one subpattern must be present. All subpatterns must bind the same set of pattern variables. (not pat 1...pat n ): matches if none of the subpatterns match. The subpatterns maynot bind any pattern variables. (? predicate pat 1...pat n ): In this pattern, predicate must be an expression evaluating to a single argument function. This pattern matches if predicate applied to the corresponding value is true, and the subpatterns pat 1...pat n all match. The predicate should not have side effects, as the code generated bythe pattern matcher mayinvoke predicates repeatedlyin anyorder. The predicate expression is bound in the same scope as the match expression, ie., free variables in predicate are not bound by pattern variables. (set! identifier): matches anything, and binds identifier to a procedure of one argument that mutates the corresponding field of the matching value. This pattern must be nested within a pair, vector, box, or structure pattern. For example, the expression: 3

1.2. Code Generation 1. Match (define x (list 1 (list 23))) (match x [(_ (_ (set! setit))) (setit 4)]) mutates the cadadr of x to 4, sothatx is (1 (24)). (get! identifier): matches anything, and binds identifier to a procedure of zero arguments that accesses the corresponding field of the matching value. This pattern is the complement to set!. As with set!, this pattern must be nested within a pair, vector, box, or structure pattern. Quasipatterns: Quasiquote introduces a quasipattern, in which identifiers are considered to be symbolic constants. Like Scheme s quasiquote for data, unquote (,) and unquote-splicing (,@) escape back to normal patterns. 1.1.2 Match Failure If no clause matches the value, the default action is to invoke the procedure match:error with the value that did not match. The default definition of match:error calls error with an appropriate message: > (match 1 [22]) Error: no clause matched 1. For most situations, this behavior is adequate, but it can be changed either byredefining match:error, or by altering the value of the variable match:error-control. Valid values for match:error-control are: match:error-control: error action: error (default) call (match:error unmatched-value) match call (match:error unmatched-value (match expression...)) fail call match:error or die in car, cdr,... unspecified return unspecified value Setting match:error-control to match causes the entire match expression to be quoted and passed as a second argument to match:error. The default definition of match:error then prints the match expression before calling error; this can help identifywhich expression failed to match. This option causes the macros to generate somewhat larger code, since each match expression includes a quoted representation of itself. Setting match:error-control to fail permits the macros to generate faster and more compact code than error or match. The generated code omits pair? tests when the consequence is to fail in car or cdr rather than call match:error. Finally, if match:error-control is set to unspecified, non-matching expressions will either fail in car or cdr, or return an unspecified value. This results in still more compact code, but is unsafe. 1.2 Code Generation Pattern matching macros are compiled into if-expressions that decompose the value being matched with standard Scheme procedures, and test the components with standard predicates. Rebinding or lexically shadowing the names of anyof these procedures will change the semantics of the match macros. The names that should not be rebound or shadowed are: 4

1. Match 1.3. Examples null? pair? number? string? symbol? boolean? char? procedure? vector? box? list? equal? car cdr cadr cdddr... vector-length vector-ref unbox reverse length call/cc Additionally, the code generated to match a structure pattern like ($ Foo pat 1...pat n ) refers to the names Foo?, Foo-1 through Foo-n, and set-foo-1! through set-foo-n!. These names also should not be shadowed. 1.3 Examples This section illustrates the convenience of pattern matching with some examples. The following function recognizes some s-expressions that represent the standard Y operator: (define Y? [( lambda (f1) ( lambda (y1) ((( lambda (x1) (f2( lambda (z1) ((x2x3) z2)))) ( lambda (a1) (f3 ( lambda (b1) ((a2a3) b2))))) y2))) (and (symbol? f1) (symbol? y1) (symbol? x1) (symbol? z1) (symbol? a1) (symbol? b1) (eq? f1 f2) (eq? f1 f3) (eq? y1 y2) (eq? x1 x2) (eq? x1 x3) (eq? z1 z2) (eq? a1 a2) (eq? a1 a3) (eq? b1 b2))] [_ #f])) Writing an equivalent piece of code in raw Scheme is tedious. The following code defines abstract syntax for a subset of Scheme, a parser into this abstract syntax, and an unparser. (define-structure (Lam args body)) (define-structure (Var s)) (define-structure (Const n)) (define-structure (App fun args)) (define parse [(and s (? symbol?) (not lambda)) (make-var s)] [(? number? n) (make-const n)] [( lambda (and args ((? symbol?)...) (not (? repeats?))) body) (make-lam args (parse body))] [(f args...) (make-app (parse f) (map parse args))] [x (error syntax "invalid expression")])) (define repeats? (lambda (l) 5

1.3. Examples 1. Match (and (not (null? l)) (or (memq (car l) (cdr l)) (repeats? (cdr l)))))) (define unparse [($\$$ Var s) s] [($\$$ Const n) n] [($\$$ Lam args body) (lambda,args,(unparse body))] [($\$$ App f args) (,(unparse f),@(map unparse args))])) With pattern matching, it is easyto ensure that the parser rejects all incorrectlyformed inputs with an error message. With match-define, it is easyto define several procedures that share a hidden variable. The following code defines three procedures, inc, value, and reset, that manipulate a hidden counter variable: (match-define (inc value reset) (let ([val 0]) (list (lambda () (set! val (add1 val))) (lambda () val) (lambda () (set! val 0))))) Although this example is not recursive, the bodies could recursivelyrefer to each other. The following code is taken from the macro package itself. The procedure validate-match-pattern checks the syntax of match patterns, and converts quasipatterns into ordinary patterns. 6

1. Match 1.3. Examples (define validate-match-pattern (lambda (p) (letrec ([name? (lambda (x) (and (symbol? x) (not (dot-dot-k? x)) (not (memq x (quasiquote quote unquote unquote-splicing? _ $\$$ and or not set! get!...)))))] [simple? (lambda (x) (or (string? x) (boolean? x) (char? x) (number? x) (null? x)))] [ordinary [(? simple? p) p] [(? name? p) p] [ _ _] [( quasiquote p) (quasi p)] [(and p ( quote _)) p] [(? pred ps...) (and (?,pred),@(map ordinary ps))] [( and ps...) (and,@(map ordinary ps))] [( or ps...) (or,@(map ordinary ps))] [( not ps...) (not (or,@(map ordinary ps)))] [( $\$$ (? name? r) ps...) ($\$$,r,@(map ordinary ps))] [(and p ( set! (? name?))) p] [(and p ( get! (? name?))) p] [(p...) (,(ordinary p)..0)] [(p (? dot-dot-k? ddk)) (,(ordinary p),ddk)] [(x. y) (cons (ordinary x) (ordinary y))] [(? vector? p) (apply vector (map ordinary (vector->list p)))] [#&p (box (ordinary p))] [p (err "invalid pattern at ~a" p)])] [quasi [(? simple? p) p] [(? symbol? p) (quote,p)] [( unquote p) (ordinary p)] [(( unquote-splicing p). ()) (ordinary p)] [(( unquote-splicing p). y) (append (ordlist p) (quasi y))] [(p...) (,(quasi p)..0)] [(p (? dot-dot-k? ddk)) (,(quasi p),ddk)] [(x. y) (cons (quasi x) (quasi y))] [(? vector? p) (apply vector (map quasi (vector->list p)))] [#&p (box (quasi p))] [p (err "invalid quasipattern at ~a" p)])] [ordlist [() ()] [(x. y) (cons (ordinary x) (ordlist y))] [p (err "invalid unquote-splicing at ~a" p)])]) (ordinary p)))) 7