First-class continuations. call/cc, stack-passing CEK machines

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

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

Scheme in Scheme: The Metacircular Evaluator Eval and Apply

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

Functional Programming. Pure Functional Programming

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

Comp 311: Sample Midterm Examination

Lexical vs. Dynamic Scope

From Syntactic Sugar to the Syntactic Meth Lab:

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

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

INTRODUCTION TO SCHEME

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

Control in Sequential Languages

An Introduction to Scheme

CS61A Midterm 2 Review (v1.1)

Sample Final Exam Questions

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

Continuations and Continuation-Passing Style

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

Call with Current Continuation Patterns

An Explicit Continuation Evaluator for Scheme

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

A Brief Introduction to Scheme (II)

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?

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

Programming Languages

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

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

An Explicit-Continuation Metacircular Evaluator

Konzepte von Programmiersprachen

6.001, Spring Semester, 1998, Final Exam Solutions Your Name: 2 Part c: The procedure eval-until: (define (eval-until exp env) (let ((return (eval-seq

Project 2: Scheme Interpreter

Closures. Mooly Sagiv. Michael Clarkson, Cornell CS 3110 Data Structures and Functional Programming

Duplication and Partial Evaluation For a Better Understanding of Reflective Languages

CS 314 Principles of Programming Languages. Lecture 16

Building a system for symbolic differentiation

Closures. Mooly Sagiv. Michael Clarkson, Cornell CS 3110 Data Structures and Functional Programming

Discussion 12 The MCE (solutions)

C311 Lab #3 Representation Independence: Representation Independent Interpreters

Turtles All The Way Down

Essentials of Programming Languages Language

Implementing Coroutines with call/cc. Producer/Consumer using Coroutines

Essentials of Programming Languages Language

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

Building a system for symbolic differentiation

CS 314 Principles of Programming Languages

LISP AND SYMBOLIC COMPUTATION: An International Journal, 7, , 1994 c 1994 Kluwer Academic Publishers Manufactured in The Netherlands

CS 342 Lecture 7 Syntax Abstraction By: Hridesh Rajan

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

Agenda. CS301 Session 9. Abstract syntax: top level. Abstract syntax: expressions. The uscheme interpreter. Approaches to solving the homework problem

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

CS 275 Name Final Exam Solutions December 16, 2016

CS450 - Structure of Higher Level Languages

The Environment Model. Nate Foster Spring 2018

Structure and Interpretation of Computer Programs

CS 314 Principles of Programming Languages

This exam is worth 70 points, or about 23% of your total course grade. The exam contains 15 questions.

Functional Programming. Pure Functional Languages

LECTURE 16. Functional Programming

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

Midterm Examination (Sample Solutions), Cmput 325

COP4020 Programming Languages. Functional Programming Prof. Robert van Engelen

Fall 2017 December 4, Scheme. Instructions

Functional Programming. Pure Functional Languages

Wellesley College CS251 Programming Languages Spring, 2000 FINAL EXAM REVIEW PROBLEM SOLUTIONS

First-Class Synchronization Barriers. Franklyn Turbak Wellesley College

The Environment Model

CS 360 Programming Languages Interpreters

Normal Order (Lazy) Evaluation SICP. Applicative Order vs. Normal (Lazy) Order. Applicative vs. Normal? How can we implement lazy evaluation?

6.821 Jeopardy: The Home Version The game that turns into 6.82fun!

4.2 Variations on a Scheme -- Lazy Evaluation

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

Programming Languages. Thunks, Laziness, Streams, Memoization. Adapted from Dan Grossman s PL class, U. of Washington

SCHEME 10 COMPUTER SCIENCE 61A. July 26, Warm Up: Conditional Expressions. 1. What does Scheme print? scm> (if (or #t (/ 1 0)) 1 (/ 1 0))

Scheme as implemented by Racket

MASSACHVSETTS INSTITVTE OF TECHNOLOGY Department of Electrical Engineering and Computer Science. Issued: Wed. 26 April 2017 Due: Wed.

Documentation for LISP in BASIC

A brief tour of history

6.037 Lecture 7B. Scheme Variants Normal Order Lazy Evaluation Streams

Lazy Evaluation and Parameter Transfer

CSc 520 Principles of Programming Languages

Principles of Programming Languages Topic: Scope and Memory Professor Louis Steinberg Fall 2004

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

References and Mutable Data Structures

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

CONCEPTS OF PROGRAMMING LANGUAGES Solutions for Mid-Term Examination

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

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

Sequentialising a concurrent program using continuation-passing style

Fall 2017 December 4, 2017

Problem 1: Binary Trees: Flatten

Programming Languages. Function-Closure Idioms. Adapted from Dan Grossman's PL class, U. of Washington

Pattern Matching for Scheme

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

Typed Racket: Racket with Static Types

The Typed Racket Reference

CSE341 Autumn 2017, Final Examination December 12, 2017

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

CPS 506 Comparative Programming Languages. Programming Language Paradigm

Transcription:

First-class continuations call/cc, stack-passing CEK machines

But first Assignment 2

e ::= (letrec* ([x e]...) e) (letrec ([x e]...) e) (let* ([x e]...) e) (let ([x e]...) e) (let x ([x e]...) e) (lambda (x...) e) (lambda x e) (lambda (x...+. x) e) (dynamic-wind e e e) (guard (x cond-clause ) e) (raise e) (delay e) (force e) (and e...) (or e...) (cond cond-clause...) (case e case-clause...) (if e e e) (when e e) (unless e e) (set! x e) (begin e...+) (call/cc e) (apply e e) (e e...) x op (quote dat)

e ::= (let ([x e]...) e) (lambda (x...) e) (lambda x e) (apply e e) (e e...) (prim op e ) (apply-prim op e) (if e e e) (set! x e) (call/cc e) x (quote dat)

utils.rkt prim? reserved? scheme-exp? ir-exp? eval-scheme eval-ir

Write your own tests./tests/*/mytest.scm (require utils.rkt ) (require desugar.rkt ) (define scm (read (open-input-file ))) (scheme-exp? scm) scm (define ir (desugar scm)) (ir-exp? ir) ir (eval-ir ir)

start-0 (solved with only prims and quote) (+ 5 6) (prim + 5 6)

start-1 (solved once you add forms in both langs such as let, ) (let ([x 1] (let ([_ (set! x 2)]) (+ x y) ))

(unless e0 e1) (if e0 (void) e1)

(case ek [(d0 d1) ebdy] clauses ) (let ([t ek]) (if (memv t (d0 d1)) ebdy (case t clauses )))

promises (delay e) (force e) promise? Delay wraps its body in a thunk to be executed later by a force form. A promise is returned. Prim promise? should desugar correctly. Forcing a promise evaluates and saves the value.

call/cc

((((λ (u) (u u)) (λ (a) a)) e1) e0)

((((λ (u) (u u)) (λ (a) a)) e1) e0) E = (( e1) e0) r = ((λ (u) (u u)) (λ (a) a))

((((λ (u) (u u)) (λ (a) a)) e1) e0) E = (( e1) e0) r = ((λ (u) (u u)) (λ (a) a)) (λ (z) (((λ (u) (u u)) (λ (a) a)) z))

η - expansion & thunking allows us to take hold of a suspended first-class computation (a call site) we may apply later.

call/cc allows us to take hold of a suspended first-class computation (a return point) we may apply later.

(((call/cc (λ (k) (k (λ )))) e1) e0) E = (( e1) e0) r = (call/cc (λ (k) (k (λ )))) ((λ (k) (k (λ ))) (λ ( ) (( e1) e0))) ((λ ( ) (( e1) e0))) (λ )) (((λ ) e1) e0)))

Example 1. Preemptive function return

(define (fun x) (let ([y (if (p? x) )]) (g x y)))

(define (fun x) (call/cc (lambda (return) (let ([y (if (p? x) (return x))]) (g x y)))))

Example 2. Coroutines / cooperative threading Suggested exercise.

(lambda (yield) (let loop ([n 0])) (yield n) (loop (+ n 1)))

(define (coroutine->gen co) (define resume co) (lambda () (call/cc (lambda (return) (define yield (lambda (v) (call/cc (lambda (r) (set! resume r) (return v))))) (resume yield)))))

Example 3. Backtracking search

(let ([a (amb '(1 2 3 4 5 6))] [b (amb '(1 2 3 4 5 6))] [c (amb '(1 2 3 4 5 6))]) ;(pretty-print `(trying,a,b,c)) (assert (= (+ (* a a) (* b b)) (* c c))) `(solution,a,b,c))

(define (amb lst) (let ([cc (call/cc (lambda (u) (u u)))]) (if (null? lst) (fail) (let ([head (car lst)]) (set! lst (cdr lst)) (set! ccstack (cons cc ccstack)) head))))

(define ccstack ()) (define (fail) (if (null? ccstack) (error 'no-solution) (let ([next-cc (car ccstack)]) (set! ccstack (cdr ccstack)) (next-cc next-cc)))) (define (assert t) (if t (void) (fail)))

dynamic-wind & call/cc

(dynamic-wind e0 e1 e2)

(dynamic-wind (lambda () entry code) (lambda () body) (lambda () exit code))

call/cc opens source file and scans to last position closes file

call/cc read-k opens source file and scans to last position closes file

call/cc (read-k write-k) opens target file and scans to last position closes file opens source file and scans to last position closes file

Exceptions (guard [x cond-clause ] e) (raise e) Guard obtains the current continuation and then uses dynamic wind to set / unset a current handler Raise simply invokes the current handler on a value Guard s continuation should be outside the dynamic-wind so repeated raises don t infinite loop! Wrap exceptions in a cons cell if using this idiom:

(raise e) => (%handler (cons e ())) (guard [x clauses ] body) => (let ([cc (call/cc (lambda (k) k))]) (if (cons? cc) ; handle the raised exception (dynamic-wind setup-new-handler (lambda () body) revert-to-old-handler)))

Stack-passing (CEK) semantics

C Control-expression Term-rewriting / textual reduction Context and redex for deterministic eval CE Control & Env machine Big-step, explicit closure creation CES Store-passing machine Passes addr->value map in evaluation order CEK Stack-passing machine Passes a list of stack frames, small-step

(e0, env) ((λ (x) e2), env ) (e1, env) v1 (e2, env [x v1]) v2 ((e0 e1), env) v2 ((λ (x) e), env) ((λ (x) e), env) (x, env) env(x)

Previously (e0 e1), env e, env

Previously e0 e1 (e0 e1), env e, env

e ::= (λ (x) e) (e e) x (call/cc (λ (x) e))

k ::= () ar(e, env, k) fn(v, k) e ::= (λ (x) e) (e e) x (call/cc (λ (x) e))

k ::= () ar(e, env, k) fn(v, k) e ::= (λ (x) e) (e e) x (call/cc (λ (x) e)) E ::= (E e) (v E)

((e0 e1), env, k) (e0, env, ar(e1, env, k)) (x, env, ar(e1, env1, k1)) (e1, env1, fn(env(x), k1)) ((λ (x) e), env, ar(e1, env1, k1)) (e1, env1, fn(((λ (x) e), env), k1)) (x, env, fn(((λ (x1) e1), env1), k1)) (e1, env1[x1 env(x)], k1) ((λ (x) e), env, fn(((λ (x1) e1), env1), k1)) (e1, env1[x1 ((λ (x) e), env)], k1)

call/cc semantics ((call/cc (λ (x) e0)), env, k) (e0, env[x k], k) ((λ (x) e0), env, fn(k0, k1)) ((λ (x) e0), env, k0) (x, env, fn(k0, k1)) (x, env, k0)

e ::=... (let ([x e0]) e1) k ::= let(x, e, env, k) (x, env, let(x1, e1, env1, k1)) (e1, env1[x1 env(x)], k1) ((λ (x) e), env, let(x1, e1, env1, k1)) (e1, env1[x1 ((λ (x) e), env)], k1)

e ::=... (let ([x e0]) e1) (x, env, fn(((λ (x1) e1), env1), k1)) (e1, env1[x1 env(x)], k1) ((λ (x) e), env, fn(((λ (x1) e1), env1), k1)) (e1, env1[x1 ((λ (x) e), env)], k1) k ::= let(x, e, env, k) (x, env, let(x1, e1, env1, k1)) (e1, env1[x1 env(x)], k1) ((λ (x) e), env, let(x1, e1, env1, k1)) (e1, env1[x1 ((λ (x) e), env)], k1)

CEK-machine evaluation (e0, [], ()) (x, env, ()) env(x)

Implementing dynamic-wind

; Finds the maximum shared tail of two lists (define (%common-tail st0 st1) (let ([lx (length x)] [ly (length y)]) (let loop ([x (if (> lx ly) (drop x (- lx ly)) x)] [y (if (> ly lx) (drop y (- ly lx)) y)]) (if (eq? x y) x (loop (cdr x) (cdr y))))))

; Winds down old stack and up new stack, ; invoking the proper post and then pre thunks as it winds (define (%do-wind new-stack) (unless (eq? new-stack %wind-stack) (let ([tail (%common-tail new-stack %wind-stack)]) (let loop ([st %wind-stack]) (unless (eq? st tail) (set! %wind-stack (cdr st)) ((cdr (car st))) (loop (cdr st)))) (let loop ([st new-stack]) (unless (eq? st tail) (loop (cdr st))) ((car (car st))) (set! %wind-stack st)))))

(define %wind-stack ()) (define (dynamic-wind pre body post) (pre) (set! %wind-stack (cons (cons pre post) %wind-stack)) (let ([val (body)]) (set! %wind-stack (cdr %wind-stack)) (post) v))

(define (desugar-t e) (match e... ; desugar call/cc so that each use saves the stack & ; wraps resulting continuation with a call to %do-wind [`(call/cc,e0) `(call/cc,(desugar-t e0))]...))

(define (desugar-t e) (match e... ; desugar call/cc so that each use saves the stack & ; wraps resulting continuation with a call to %do-wind [`(call/cc,e0) `(call/cc,(desugar-t `(lambda (k) (,e0 (lambda (x) (k x))))))]...))

(define (desugar-t e) (match e... ; desugar call/cc so that each use saves the stack & ; wraps resulting continuation with a call to %do-wind [`(call/cc,e0) `(call/cc,(desugar-t `(lambda (k) ; save k and k s stack (,e0 (let ([k-stack %wind-stack]) (lambda (x) (begin (%do-wind k-stack) (k x))))))))]...))