Metaprogramming in SML: PostFix and S-expressions

Similar documents
Metaprogramming in SML: PostFix and S-expressions

CS251 Programming Languages Spring 2016, Lyn Turbak Department of Computer Science Wellesley College

Interpre'ng and Compiling Intex

Interpre'ng and Compiling Intex SOLUTIONS

Interpre'ng and Compiling Intex

PostFix. PostFix command semanccs (except exec) PostFix Syntax. A PostFix Interpreter in Racket. CS251 Programming Languages Fall 2017, Lyn Turbak

PostFix. PostFix command semanccs (except exec) PostFix Syntax. A PostFix Interpreter in Racket. CS251 Programming Languages Spring 2018, Lyn Turbak

Valex: Mul*ple Value Types, Condi*onals, Dynamic Type Checking and Desugaring SOLUTIONS

Sum-of-Product Data Types

Valex: Mul*ple Value Types, Condi*onals, Dynamic Type Checking and Desugaring

Sum-of-Product Data Types

CS251 Programming Languages Handout # 29 Prof. Lyn Turbak March 7, 2007 Wellesley College

Valex: Primitive Operators and Desugaring

Bindex: Naming, Free Variables, and Environments SOLUTIONS

Problem Set 5 Due:??

Bindex: Naming, Free Variables, and Environments

CS301 Compiler Design and Implementation Handout # 18 Prof. Lyn Turbak February 19, 2003 Wellesley College

Introduc)on To Standard ML

List Processing in SML

List Processing in SML

Sum-of-Product (SOP) Datatypes in SML

Exercises on ML. Programming Languages. Chanseok Oh

Design Concepts in Programming Languages Scheme Supplement

Functions & First Class Function Values

CSE341 Autumn 2017, Midterm Examination October 30, 2017

CSE 341 Section 5. Winter 2018

CSE 341 : Programming Languages Midterm, Spring 2015

Hofl, a Higher-order Functional Language. 1 An Overview of Hofl. 2 Abstractions and Function Applications

Two approaches to writing interfaces

CPSC 411, 2015W Term 2 Midterm Exam Date: February 25, 2016; Instructor: Ron Garcia

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

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

CS115 - Module 9 - filter, map, and friends

Haskell Scripts. Yan Huang

FOFL and FOBS: First-Order Functions

CSE341, Spring 2013, Final Examination June 13, 2013

CSE 341 Lecture 9. type systems; type safety; defining types Ullman 6-6.2; 5.3. slides created by Marty Stepp

Outline. Introduction Concepts and terminology The case for static typing. Implementing a static type system Basic typing relations Adding context

Metaprogramming: InterpretaBon

abstype 'a queue = q of 'a list with val Null = q([]) fun front(q(h::_)) = h fun rm(q(_::t)) = q(t) fun enter(v,q(l)) = q(rev(v::rev(l))) end

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

A Third Look At ML. Chapter Nine Modern Programming Languages, 2nd ed. 1

CSE450. Translation of Programming Languages. Lecture 11: Semantic Analysis: Types & Type Checking

Chapter 2 SML, a Functional Programming Language

Control in Sequential Languages

2.1. Expressions. Chapter 2 SML, a Functional Programming Language. Integers. Interacting with ML

Honu. Version November 6, 2010

2.1. Expressions. Chapter 2 ML, a Functional Programming Language. Integers. Interacting with ML

Lab 6: P.S. it s a stack Due 11:59 pm Monday, Mar 31, 2008

Intermediate Representations

List Processing in Ocaml

Lists, loops and decisions

1 Lexical Considerations

Problem Set 6 (Optional) Due: 5pm on Thursday, December 20

Type-indexed functions in Generic Haskell

Parsing Scheme (+ (* 2 3) 1) * 1

CS115 - Module 10 - General Trees

6.821 Programming Languages Handout Fall MASSACHVSETTS INSTITVTE OF TECHNOLOGY Department of Electrical Engineering and Compvter Science

Expressions and Assignment

Lecture 2: The Basis of SML

Lecture 8: Simple Calculator Application

Pattern Matching and Abstract Data Types

CSc 372. Comparative Programming Languages. 4 : Haskell Basics. Department of Computer Science University of Arizona

CSc 372 Comparative Programming Languages. 4 : Haskell Basics

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

Data Structures and Algorithms

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

Denotational Semantics

Overview. Factorial Revisited. Iteration via Tail Recursion in Racket. An itera*ve approach to factorial. What is itera*on?

CSE3322 Programming Languages and Implementation

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

GAWK Language Reference Manual

CS1622. Semantic Analysis. The Compiler So Far. Lecture 15 Semantic Analysis. How to build symbol tables How to use them to find

6.821 Programming Languages Handout Fall MASSACHVSETTS INSTITVTE OF TECHNOLOGY Department of Electrical Engineering and Compvter Science

CS109A ML Notes for the Week of 1/16/96. Using ML. ML can be used as an interactive language. We. shall use a version running under UNIX, called

Higher-Order Functions

Finish Lec12 TREES, PART 2. Announcements. JavaHyperText topics. Trees, re-implemented. Iterate through data structure 3/7/19

A Brief Introduction to Standard ML

Comp 311: Sample Midterm Examination

CS3110 Spring 2016 Lecture 6: Modules

A Second Look At ML. Chapter Seven Modern Programming Languages, 2nd ed. 1

Project Compiler. CS031 TA Help Session November 28, 2011

15 150: Principles of Functional Programming. Exceptions

Introduction to Programming, Aug-Dec 2006

Top Level Environment Comparison

Project 3 Due October 21, 2015, 11:59:59pm

Ruby: Introduction, Basics

Some Advanced ML Features

A First Look at ML. Chapter Five Modern Programming Languages, 2nd ed. 1

CSc 520. Principles of Programming Languages 11: Haskell Basics

Harvard School of Engineering and Applied Sciences CS 152: Programming Languages

Announcements. Project 2: released due this sunday! Midterm date is now set: check newsgroup / website. Chapter 7: Translation to IR

CS558 Programming Languages

Principles of Programming Languages

CS 112 Introduction to Computing II. Wayne Snyder Computer Science Department Boston University

CSCC24 Functional Programming Typing, Scope, Exceptions ML

CSE 341, Autumn 2005, Assignment 3 ML - MiniML Interpreter

Australian researchers develop typeface they say can boost memory, that could help students cramming for exams.

CS558 Programming Languages

CS558 Programming Languages

Transcription:

Metaprogramming in SML: PostFix and S-expressions CS251 Programming Languages Spring 2017, Lyn Turbak Department of Computer Science Wellesley College Recall the Racket PostFix Interpreter ;; Contents of postfix-fancy-transform.rkt (define (postfix-run pgm args) ) (define (postfix-exec-commands cmds init-stk) ) (define (postfix-exec-command cmd stk) ) (define (postfix-program? sexp) ) (define postfix-arithops ) (define postfix-relops ) many more definitions ;; Sample program from lecture (define pf1 '(postfix 2 2 nget 0 gt (sub) (swap 1 nget mul add) sel exec)) > (postfix-run '(postfix 2 1 nget mul swap 1 nget mul add) '(3 4)) 25 > (map (λ (args) (postfix-run pf1 args)) '((3 5) (3-5))) '(2 28) PostFix and Sexps in SML 2 Our Goal is Something Similar in SML - testrun' "(postfix 2 1 nget mul swap 1 nget mul add)" "(3 4)"; val it = "25" : string - val pf1string = "(postfix 2 2 nget 0 gt (sub) (swap 1 nget mul add) sel exec)"; val pf1string = "(postfix 2 2 nget 0 gt (sub) (swap 1 nget mul add) sel exec)" : string - map (testrun' pf1string) ["(3 5)", "(3-5)"]; val it = ["2","28"] : string list Along the way we will see: RepresenFng PostFix programs with sum-of-product datatypes Leveraging pahern matching in the PostFix interpreter ConverFng between string and sum-of-product representafons of a Racket-like S-expression datatype. PostFix and Sexps in SML 3 PostFix SyntacFc Data Types All PostFix code in these slides is from ~wx/cs251/sml/postfix/postfix.sml datatype pgm = PostFix of int * cmd list and cmd = Pop Swap Nget Sel Exec Int of int Seq of cmd list Arithop of arithop Relop of relop and arithop = Add Sub Mul Div Rem and relop = Lt Eq Gt (* SML syntax corresponding to s-expression syntax (postfix 2 2 nget 0 gt (sub) (swap 1 nget mul add) sel exec)) *) val pf1 = PostFix(2, [Int 2, Nget, Int 0, Relop Gt, Seq[Arithop Sub], Seq[Swap, Int 1, Nget, Arithop Mul, Arithop Add], Sel, Exec]) PostFix and Sexps in SML 4

PostFix Interpreter (* Stack values are either ints or executable seqs *) datatype stkval = IntVal of int SeqVal of cmd list exception ConfigError of string * cmd * stkval list (* config errors *) exception ExecError of string (* other runtime errors *) (* val run : pgm -> int list -> int *) fun run (PostFix(numargs, cmds)) args = if numargs = List.length args then case execcmds cmds (map IntVal args) of (IntVal v) :: _ => v _ => raise ExecError "Command sequence on top of final stack" else raise ExecError "Mismatch between expected and actual ^ "number of args (* val execcmds : cmd list -> stkval list -> stkval list *) and execcmds cmds vs = foldl (fn (cmd,stk) => execcmd cmd stk) vs cmds (* val execcmd : cmd -> stkval list -> stkval list *) and execcmd see the next page (* Perform command on given stack and return resulting stack *) and execcmd (Int i) vs = (IntVal i) :: vs execcmd (Seq cmds) vs = (SeqVal cmds) :: vs execcmd Pop (v :: vs) = vs execcmd Swap (v1 :: v2 :: vs) = v2 :: v1 :: vs execcmd Nget (stk as (IntVal index) :: vs) = if index <= 0 orelse index > List.length(vs) then raise ConfigError("Invalid index", Nget, stk) else (case List.nth(vs, index-1) of (v as IntVal(_)) => v :: vs SeqVal(_) => raise ConfigError(", Nget, stk)) execcmd Nget ((IntVal index) :: vs) = (case List.nth(vs, index-1) of (v as IntVal(_)) => v :: vs SeqVal(_) => raise ExecError "Nget can't get a command sequence") execcmd Nget ((IntVal index) :: vs) = List.nth(vs, index-1) :: vs execcmd Sel (v_else :: v_then :: (IntVal v_test) :: vs) = (if v_test = 0 then v_else else v_then) :: vs execcmd Exec ((SeqVal cmds) :: vs) = execcmds cmds vs execcmd (Arithop a) ((IntVal i1) :: (IntVal i2) :: vs) = (IntVal ((arithoptofun a)(i2, i1)) ) :: vs execcmd (Relop r) ((IntVal i1) :: (IntVal i2) :: vs) = (IntVal (booltoint( ((reloptofun r)(i2, i1)) ) ) ) :: vs execcmd cmd stk = raise ConfigError("Illegal configuration", cmd, stk) and arithoptofun Add = op+ arithoptofun Mul = op* arithoptofun Sub = op- arithoptofun Div = (fn(x,y) => x div y) arithoptofun Rem = (fn(x,y) => x mod y) and reloptofun Lt = op< reloptofun Eq = op= reloptofun Gt = op> execcmd PostFix and Sexps in SML 5 and booltoint false = 0 booltoint true = 1 PostFix and Sexps in SML 6 Try it out - run pf1 [3,5]; val it = 2 : int - run pf1 [3,~5]; val it = 28 : int What About Errors? - run (PostFix(1,[Arithop Add])) [3] ;uncaught exception ExecError raised at: postfix.sml: 49.25-49.61 - run (PostFix(1,[Seq [Arithop Add]])) [3] ;uncaught exception ExecError raised at: postfix.sml: 33.17-33.59 - run (PostFix(1,[Exec])) [3] ;uncaught exception ExecError raised at: postfixsolns.sml:49.25-49.61 - run (PostFix(1,[Int 0, Arithop Div])) [3] ;uncaught exception Div [divide by zero] raised at: postfix-solns.sml:57.38-57.41 PostFix and Sexps in SML 7 Problems: 1. No error message printed 2. Stops at first error in a sequence of tests PostFix and Sexps in SML 8

SML ExcepFon Handling with handle fun testrun pgm args = Int.toString (run pgm args) (* nonerrors & errors must be same type! *) handle ExecError msg => "ExecError: " ^ msg General.Div => "Divide by zero error (* General.Div from SML General basis structure; Need explicit qualification to distinguish from PostFix.Div *) other => "Unknown exception: " ^ (exnmessage other) - testrun pf1 [3,~5]; val it = "28" : string (* no error here; returns int as string *) Errors no longer halt execufon/tesfng - map (fn args => testrun (PostFix(2, [Arithop Div])) args) = [[3,7], [2,7], [0,5], [4,17]]; val it = ["2","3","Divide by zero error","4"] : string list - testrun (PostFix(1,[Arithop Add])) [3]; val it = "ExecError: Unexpected Configuration" : string (* could modify program to give configuration details *) - testrun (PostFix(1,[Seq [Arithop Add]])) [3]; val it = "ExecError: Sequence on top of final stack" : string - testrun (PostFix(1,[Exec])) [3]; val it = "ExecError: Unexpected Configuration" : string - testrun (PostFix(1,[Int 0, Arithop Div])) [3]; val it = "Divide by zero error" : string PostFix and Sexps in SML 9 PostFix and Sexps in SML 10 ExcepFon Handling in other Languages SML s raise & handle like Java s throw and try/catch JavaScript s throw and try/catch Python s raise & try/except No need for try in SML; you can ahach handle to any expression (but might need to add extra parens). Result types of expression and its handlers must be the same! S-expression vs SOP program representafons '(postfix 2 2 nget 0 gt (sub) (swap 1 nget mul add) sel exec) PostFix(2, [Int 2, Nget, Int 0, Relop Gt, Seq[Arithop Sub], Seq[Swap, Int 1, Nget, Arithop Mul, Arithop Add], Sel, Exec]) S-expression notafon is more compact Sum-of-product notafon allows wrifng program directly as instance(s) of program dataype(s), which supports interpretafon based on pahern matching Can we somehow get the advantages of both? PostFix and Sexps in SML 11 PostFix and Sexps in SML 12

Idea: convert between SOP and S-expression reps using intermediate Sexp datatype "(postfix 2 (1 nget mul) exec add)" Sexp.stringToSexp Sexp.Seq[Sexp.Sym "postfix", Sexp.Int 2, Sexp.Seq[Sexp.Int 1, Sexp.Sym "nget", Sexp.Sym "mul"], Sexp.Sym "exec", Sexp.Sym "add"] Parse from Sexp: PostFix.sexpToPgm S-expression as string Sexp.sexpToString Unparse to Sexp: PostFix.pgmToSexp S-expression as instance of Sexp datatype Sexp dataytype signature SEXP = sig datatype sexp = Int of int Flt of real Str of string Chr of char Sym of string Seq of sexp list exception IllFormedSexp of string val isequal : sexp * sexp -> bool val stringtosexp : string -> sexp val stringtosexps : string -> sexp list val filetosexp : string -> sexp val filetosexps : string -> sexp list val sexptostring : sexp -> string val sexptostring' : int -> sexp -> string val sexpstostring : sexp list -> string val sexptofile : sexp -> string -> unit val readsexp : unit -> sexp end This SEXP signature and Sexp structure can be found in ~wx/cs251/sml/sexp PostFix(2, [Seq[Int 1, Nget, Arithop Mul], Exec, Arithop Add]) SOP representafon PostFix and Sexps in SML 13 structure Sexp :> SEXP = struct end You can treat the Sexp structure As a black box. You needn t Understand how it works. PostFix and Sexps in SML 14 Sexp examples - Sexp.stringToSexp "(17 3.141 'c' \"foo bar\" (\"baz quux\" 1.5 42))"; (* Need to escape nested double quotes *) val it = Seq [Int 17,Flt 3.141,Chr #"c",str "foo bar, Seq [Str "baz quux",flt 1.5,Int 42]] : Sexp.sexp - Sexp.sexpToString it; val it = "(17 3.141 'c' \"foo bar\" (\"baz quux\" 1.5 42))" : string - Sexp.stringToSexps "5 2.7 'Q' \"cs251\" () (1) (2 3)"; val it = [Int 5,Flt 2.7,Chr #"Q",Str "cs251",seq [],Seq [Int 1],Seq [Int 2,Int 3]] : Sexp.sexp list Can read sexps from files: ; Contents of pgms.sexp (postfix 2 1 nget mul) ; simple PostFix program { ; Curly braces are nestable block comments (postfix 1) ; silly program { (intex 0 17) ; Another silly program } } (intex 2 (/ (+ ($ 1) ($ 2)) 2)) ; Intex averaging program - Sexp.fileToSexps "pgms.sexp"; val it = [Seq [Sym "postfix",int 2,Int 1,Sym "nget",sym "mul ], Seq [Sym "intex",int 2, Seq [Sym "/", Seq [Sym "+",Seq [Sym "$",Int 1], Seq [Sym "$",Int 2]], Int 2]]] : Sexp.sexp list (* The above output has been reformatted to enhanced readability. Note that line and block comments are ignored *) PostFix and Sexps in SML 15 PostFix and Sexps in SML 16

Parsing sexps to PostFix.cmd and PostFix.pgm exception SyntaxError of string fun sexptopgm (Sexp.Seq(Sexp.Sym "postfix" :: Sexp.Int n :: cmdxs)) = PostFix(n, map sexptocmd cmdxs) sexptopgm sexp = raise (SyntaxError ("invalid PostFix program: " ^ (Sexp.sexpToString sexp)) and sexptocmd (Sexp.Int i) = Int i sexptocmd (Sexp.Seq cmdxs) = Seq (map sexptocmd cmdxs) sexptocmd (Sexp.Sym "pop") = Pop sexptocmd (Sexp.Sym "swap") = Swap sexptocmd (Sexp.Sym "nget") = Nget sexptocmd (Sexp.Sym "sel") = Sel sexptocmd (Sexp.Sym "exec") = Exec sexptocmd (Sexp.Sym "add") = Arithop Add sexptocmd (Sexp.Sym "sub") = Arithop Sub sexptocmd (Sexp.Sym "mul") = Arithop Mul sexptocmd (Sexp.Sym "div") = Arithop Div sexptocmd (Sexp.Sym "rem") = Arithop Rem sexptocmd (Sexp.Sym "lt") = Relop Lt sexptocmd (Sexp.Sym "eq") = Relop Eq sexptocmd (Sexp.Sym "gt") = Relop Gt PostFix parsing examples - map stringtocmd ["3", "pop", "add", "lt", "(1 nget mul)"]; val it = [Int 3,Pop,Arithop Add,Relop Lt,Seq [Int 1,Nget,Arithop Mul]] : cmd list - stringtopgm "(postfix 2 2 nget 0 gt (sub) (swap 1 nget mul add) sel exec)"; val it = PostFix (2, [Int 2,Nget,Int 0,Relop Gt,Seq [Arithop Sub], Seq [Swap,Int 1,Nget,Arithop Mul,Arithop Add], Sel,Exec]) : pgm and stringtocmd s = sexptocmd (Sexp.stringToSexp s) and stringtopgm s = sexptopgm (Sexp.stringToSexp s) PostFix and Sexps in SML 17 PostFix and Sexps in SML 18 testrun' takes sexp strings We ve achieved our goal from beginning of lecture exception SexpError of string * Sexp.sexp fun testrun' pgmsexpstring argssexpstring = testrun (stringtopgm pgmsexpstring) (sexpstringtointlist argssexpstring) handle SexpError (msg, sexp) => ("SexpError: " ^ msg ^ " " ^ (Sexp.sexpToString sexp)) Sexp.IllFormedSexp msg => ("SexpError: Ill-formed sexp " ^ msg) other => "Unknown exception: " ^ (exnmessage other) and sexpstringtointlist str = let val sexp = Sexp.stringToSexp str in case sexp of Sexp.Seq xs => map sexptoint xs _ => raise SexpError("expected sexp sequence but got", sexp) end and sexptoint (Sexp.Int i) = i sexptoint sexp = raise SexpError("expected sexp int but got", sexp) - testrun' "(postfix 2 1 nget mul swap 1 nget mul add)" "(3 4)"; val it = "25" : string - val pf1string = "(postfix 2 2 nget 0 gt (sub) (swap 1 nget mul add) sel exec)"; val pf1string = "(postfix 2 2 nget 0 gt (sub) (swap 1 nget mul add) sel exec)" : string - map (testrun' pf1string) ["(3 5)", "(3-5)"]; val it = ["2","28"] : string list (* The following examples illustrate some error cases *) - testrun' "(postfix 1 1 get mul)" "(3)"; val it = "SyntaxError: unknown command get" : string - testrun' "(postfix 1 1 nget mul" "(3) val it = "SexpError: Ill-formed sexp Sexp: end of input before matching right paren -- (postfix 1 1 nget mul - testrun' "(postfix nget mul)" "(3) ; val it = "SyntaxError: invalid PostFix program: (postfix nget mul)" : string - testrun' "(postfix 1 1 nget mul)" "3"; val it = "SexpError: expected sexp sequence but got 3" : string PostFix and Sexps in SML 19 PostFix and Sexps in SML 20

Unparsing PostFix.pgm and PostFix.cmd to sexps fun pgmtosexp (PostFix(n,cmds)) = Sexp.Seq (Sexp.Sym "postfix" :: Sexp.Int n :: map cmdtosexp cmds) and cmdtosexp (Int i) = Sexp.Int i cmdtosexp (Seq cmds) = Sexp.Seq (map cmdtosexp cmds) cmdtosexp Pop = Sexp.Sym "pop" cmdtosexp Swap = Sexp.Sym "swap" cmdtosexp Nget = Sexp.Sym "nget" cmdtosexp Sel = Sexp.Sym "sel" cmdtosexp Exec = Sexp.Sym "exec" cmdtosexp (Arithop Add) = Sexp.Sym "add" cmdtosexp (Arithop Sub) = Sexp.Sym "sub" cmdtosexp (Arithop Mul) = Sexp.Sym "mul" cmdtosexp (Arithop Div) = Sexp.Sym "div" cmdtosexp (Arithop Rem) = Sexp.Sym "rem" cmdtosexp (Relop Lt) = Sexp.Sym "lt" cmdtosexp (Relop Eq) = Sexp.Sym "eq" cmdtosexp (Relop Gt) = Sexp.Sym "gt" PostFix unparsing example - pgmtostring(postfix(2, [Int 1, Nget, Int 3, Nget, Relop Lt, = Seq[Arithop Sub], = Seq[Swap, Int 1, Nget, Arithop Mul, Swap, Arithop Add], = Sel, Exec])); val it = "(postfix 2 1 nget 3 nget lt (sub) (swap 1 nget mul swap add) sel exec)" : string and cmdtostring s = Sexp.sexpToString (cmdtosexp s) and pgmtostring s = Sexp.sexpToString (pgmtosexp s) PostFix and Sexps in SML 21 PostFix and Sexps in SML 22