Part I: Written Problems

Similar documents
Part I: Written Problems

CSE341 Spring 2016, Midterm Examination April 29, 2016

CSE 341 Section 5. Winter 2018

CSE341 Spring 2016, Midterm Examination April 29, 2016

CSE341, Fall 2011, Midterm Examination October 31, 2011

CSE341 Autumn 2017, Midterm Examination October 30, 2017

CSE341: Programming Languages Lecture 9 Function-Closure Idioms. Dan Grossman Winter 2013

A Concepts-Focused Introduction to Functional Programming Using Standard ML Sample Exam #1 Draft of August 12, 2010

CSE341, Fall 2011, Midterm Examination October 31, 2011

CSE341: Programming Languages Lecture 4 Records, Datatypes, Case Expressions. Dan Grossman Spring 2013

CSE341 Spring 2017, Midterm Examination April 28, 2017

CSE341: Programming Languages Lecture 9 Function-Closure Idioms. Dan Grossman Fall 2011

CSci 4223 Principles of Programming Languages

CSC324- TUTORIAL 5. Shems Saleh* *Some slides inspired by/based on Afsaneh Fazly s slides

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

CS Lecture 6: Map and Fold. Prof. Clarkson Fall Today s music: Selections from the soundtrack to 2001: A Space Odyssey

CSE341: Programming Languages Lecture 6 Nested Patterns Exceptions Tail Recursion. Zach Tatlock Winter 2018

Computer Science CSC324 Wednesday February 13, Homework Assignment #3 Due: Thursday February 28, 2013, by 10 p.m.

CSE341: Programming Languages Lecture 11 Type Inference. Dan Grossman Spring 2016

CSE341 Section 3. Standard-Library Docs, First-Class Functions, & More

CS Lecture 6: Map and Fold. Prof. Clarkson Spring Today s music: Selections from the soundtrack to 2001: A Space Odyssey

CMSC 330: Organization of Programming Languages. Functional Programming with Lists

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

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

Programming Languages and Compilers (CS 421)

Function definitions. CSE341: Programming Languages Lecture 2 Functions, Pairs, Lists. Example, extended. Some gotchas. Zach Tatlock Winter 2018

CSE341: Programming Languages Lecture 2 Functions, Pairs, Lists. Zach Tatlock Winter 2018

CSC/MAT-220: Lab 6. Due: 11/26/2018

CSE341: Programming Languages Lecture 2 Functions, Pairs, Lists. Dan Grossman Fall 2011

Lecture 3: Recursion; Structural Induction

Programming Languages

CSCI-GA Final Exam

CSE 341: Programming Languages

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

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

Lists. Prof. Clarkson Fall Today s music: "Blank Space" by Taylor Swift

Programming Languages and Techniques (CIS120)

News. Programming Languages. Recap. Recap: Environments. Functions. of functions: Closures. CSE 130 : Fall Lecture 5: Functions and Datatypes

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

CS 11 Haskell track: lecture 1

User-defined Functions. Conditional Expressions in Scheme

CSci 4223 Lecture 12 March 4, 2013 Topics: Lexical scope, dynamic scope, closures

An introduction introduction to functional functional programming programming using usin Haskell

CSCI-GA Scripting Languages

CMSC 330: Organization of Programming Languages. Functional Programming with Lists

Introduction to OCaml

Handout 2 August 25, 2008

ML Built-in Functions

List Processing in Ocaml

Haske k ll An introduction to Functional functional programming using Haskell Purely Lazy Example: QuickSort in Java Example: QuickSort in Haskell

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

Implementing nml: Hindley-Milner Type Inference

CS52 - Assignment 8. Due Friday 4/15 at 5:00pm.

CSCI 3155: Homework Assignment 3

Homework 8: Matrices Due: 11:59 PM, Oct 30, 2018

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

CSE 341 Sample Midterm #2

Mini-ML. CS 502 Lecture 2 8/28/08

CSE 341, Spring 2011, Final Examination 9 June Please do not turn the page until everyone is ready.

Begin at the beginning

CSE341, Spring 2013, Final Examination June 13, 2013

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

SML Style Guide. Last Revised: 31st August 2011

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

A quick introduction to SML

Types and Programming Languages. Lecture 5. Extensions of simple types

A Brief Introduction to Standard ML

Recap: Functions as first-class values

COMP 105 Homework: Type Systems

Warm-up and Memoization

CSE 341: Programming Languages

CMSC330 Fall 2016 Midterm #1 2:00pm/3:30pm

CSc 372, Fall 2001 Final Examination December 14, 2001 READ THIS FIRST

CSE 341 : Programming Languages Midterm, Spring 2015

News. CSE 130: Programming Languages. Environments & Closures. Functions are first-class values. Recap: Functions as first-class values

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

Functional Programming

Chapter 3 Linear Structures: Lists

Homework 5. Notes. Turn-In Instructions. Reading. Problems. Handout 19 CSCI 334: Spring (Required) Read Mitchell, Chapters 6 and 7.

Homework 7: Subsets Due: 11:59 PM, Oct 23, 2018

Programming Languages and Techniques (CIS120)

CSE3322 Programming Languages and Implementation

OCaml. ML Flow. Complex types: Lists. Complex types: Lists. The PL for the discerning hacker. All elements must have same type.

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

Chapter 3 Linear Structures: Lists

# true;; - : bool = true. # false;; - : bool = false 9/10/ // = {s (5, "hi", 3.2), c 4, a 1, b 5} 9/10/2017 4

Tail Calls. CMSC 330: Organization of Programming Languages. Tail Recursion. Tail Recursion (cont d) Names and Binding. Tail Recursion (cont d)

Tail Recursion: Factorial. Begin at the beginning. How does it execute? Tail recursion. Tail recursive factorial. Tail recursive factorial

Products and Records

Lists. Michael P. Fourman. February 2, 2010

CSc 372, Spring 1996 Mid-term Examination Solution Key

Talen en Compilers. Jurriaan Hage , period 2. November 13, Department of Information and Computing Sciences Utrecht University

CSE341 Autumn 2017, Final Examination December 12, 2017

CS115 - Module 9 - filter, map, and friends

Preliminary Examination I Computer Science 312, Cornell University 6 March 2003

Datatype declarations

CSE341 Spring 2017, Final Examination June 8, 2017

CSE 341 : Programming Languages

CMSC 330: Organization of Programming Languages. OCaml Expressions and Functions

COS 126 General Computer Science Spring Written Exam 1

Transcription:

CSci 4223 Homework 3 DUE: Friday, March 22, 11:59 pm Instructions. Your task is to answer 2 written problems, and to write 16 SML functions (excluding local helper functions) as well as test cases for those functions. See the end of this document for instructions on how to submit your solution. In case you re curious, our reference solution to the (non-karma) programming problems contains about 75 lines of code, excluding comments, blank lines, and the provided code described next. Provided code. Download hw3template.sml from the course website. The provided code defines several datatypes, as well as a function and a type synonym, for you; you may not change those. Prohibitions. You may not use mutable references or arrays. You must use good style. Recall that using pattern matching is typically better style than using functions like hd and selectors like #1. Library functions. Several of the problems on this homework point you to functions in the Standard ML Basis Library. Documentation of that library is available at http://www.standardml.org/basis/ manpages.html. Part I: Written Problems Problem 1. Consider the following curried, higher-order functions: fun K x y = x fun S x y z = x z (y z) These two functions are remarkably powerful. A. What is the value that results from evaluating S K K 17? B. Define a KS expression to be an ML expression that uses only K, S, and spaces. Give a KS expression I such that the result of evaluating I is a function whose behavior is identical to the function fn x => x. C. Define an KSI expression to be an ML expression that uses only K, S, I, and spaces. Consider the following two functions: fun t x y = x fun f x y = y Give a KSI expression, call it T, whose behavior is equivalent to t. And give a KSI expression, call it F, whose behavior is equivalent to f. D. Give a KSI expression, call it OR, such that OR interacts with T and F like logical or. That is, your expression should have the following behavior: T OR T = T T OR F = T F OR T = T F OR F = F Hint: the answers to parts B, C, and D are each three characters or fewer, excluding spaces. 1

Problem 2. This is the last problem from Midterm 1. Since very few people solved it on the exam, you now have a second chance to solve it as a homework problem. The type-checking rules for if expressions require the guard of the expression to have type bool. (In expression if e0 then e1 else e2, the guard is e0 i.e., the expression between if and then.) In C, however, guards are required to have type int; the then branch is executed if the guard is nonzero, otherwise the else branch is executed. In C, for example, if (1) { printf("1\n"); } else { printf("0\n"); } will print 1. Let s modify ML if expressions such that guards have type int rather than bool. A. Give a new type-checking rule for ML if expressions that requires guards to have type int. Your rule should otherwise be the same as the standard ML rule. Give the entire rule, not just a fragment of it. B. To use the Boolean comparison operators with our new if expressions, they now need to return integers. Let s consider the less-than operator <. It should now be a function that takes two integers and returns an integer. Write down its new type (and just its type nothing else). C. Also, let s consider the equality operator =. It should now be a function that takes two values that can be compared for equality and returns an integer. Write down its new type (and just its type nothing else). D. Give a new evaluation rule for ML if expressions. Your rule should result in the same semantics as that given for C above. Give the entire rule. E. ML if expressions are actually syntactic sugar for case expressions. Show how to desugar our new kind of integer-guarded if expressions. That is, how should the compiler rewrite if e0 then e1 else e2 as a case expression, given your new evaluation rule from the previous part? Your answer may not use if expressions. Part II: Higher-order Functions All the solutions to these problems require only a single line of code (or perhaps two lines, because of the usual line break in a function binding after =). Beware: despite or perhaps because of their concise solutions, these problems are probably more difficult than the programming problems on homework 2. Do not write any functions or helper functions that are themselves recursive. 1. Write a function only_capitals that takes a string list and returns a string list that has only the strings in the argument that start with an uppercase letter. Assume all strings have at least 1 character. Use library functions List.filter, Char.isUpper, and String.sub. 2. Write a function longest_string1 that takes a string list and returns the longest string in the list. If the list is empty, return "". In the case of a tie, return the string closest to the beginning of the list. Use List.foldl and String.size. 3. Write a function longest_string2 that is exactly like longest_string1 except in the case of ties it returns the string closest to the end of the list. Your solution should be almost an exact copy of longest_string1. 4. Write functions longest_string_helper, longest_string3, and longest_string4 such that: longest_string3 has the same behavior as longest_string1 and longest_string4 has the same behavior as longest_string2. 2

longest_string3 and longest_string4 are defined with val-bindings and partial applications of longest_string_helper (described next). In both functions, the first argument passed to longest_string_helper should be a built-in SML operator. longest_string_helper has type (int * int -> bool) -> string list -> string (notice the currying). This function will look a lot like longest_string1 and longest_string2 but is more general because it takes a function as an argument. We deliberately leave the behavior of longest_string_helper unspecified; you need to figure it out. 5. Write a function longest_capitalized that takes a string list and returns the longest string in the list that begins with an uppercase letter (or "" if there are no such strings). Use a val-binding and the ML library s o operator for composing functions. Resolve ties like in problem 2. 6. Write a function rev_string that takes a string and returns the string that has the same characters in reverse order. Use ML s o operator, the library function rev for reversing lists, and two library functions in the STRING signature. (Browse the documentation to find the most useful functions.) Part III: Implementing Pattern Matching The remaining problems use these (data)type bindings: datatype pattern = WildcardP VariableP of string UnitP ConstP of int TupleP of pattern list ConstructorP of string * pattern datatype value = ConstV of int UnitV TupleV of value list ConstructorV of string * value type bindings = (string * value) list option Pattern matching is the problem of determining, given a value v and pattern p, whether p matches v. If so, the match produces a list of string * value pairs; the order of that list does not matter. The rules for matching are essentially a subset of those we studied in class for SML: WildcardP matches everything and produces the empty list. VariableP s matches any value v and produces the one-element list containing (s,v). UnitP matches only UnitV and produces the empty list. ConstP 42 matches only ConstV 42 (and similarly for other integers), and produces the empty list. TupleP ps matches a value of the form TupleV vs if ps and vs have the same length and for all i, the i th element of ps matches the i th element of vs. The list produced is all the lists from the nested pattern matches appended together. ConstructorP(s1,p) matches ConstructorV(s2,v) if s1 and s2 are the same string (you can compare them with =) and p matches v. The list produced is the list from the nested pattern match. Nothing else matches. In this part of the homework, you will implement these pattern matching rules. 1. (This problem uses the pattern datatype but is not really about pattern-matching.) (a) A function g has been provided to you. In an ML comment, describe in a few English sentences the arguments that g takes and what g computes not how g computes it, though you will have to understand that to determine what g computes. Note: you will write no code for this subproblem. (b) Use g to define a function count_wildcards that takes a pattern and returns how many WildcardP patterns it contains. 3

(c) Use g to define a function count_wild_and_variable_lengths that takes a pattern and returns the sum of the number of WildcardP patterns it contains and the string lengths of all the variables in the VariableP patterns it contains. Use String.size. (d) Use g to define a function count_some_var that takes a string and a pattern (as a pair) and returns the number of times the string appears as a variable in the pattern. 2. Write a function check_pat that takes a pattern and returns true if and only if all the variables appearing in the pattern are distinct from one another. (That is, they are different strings. Note that differences in the strings directly carried by ConstructorP patterns are not relevant.) Hints: The sample solution uses two helper functions. The first takes a pattern and returns a list of all the strings it uses for variables; List.foldl and @ are useful. The second takes a list of strings and decides whether it has any duplicates; List.exists is useful. Our reference solution is about 15 lines. Note: you will not need to use this function in any of the problems below. 3. Write a function all_answers of type ( a -> b list option) -> a list -> b list option (notice the 2 arguments are curried). The first argument should be applied to elements of the second argument. If it returns NONE for any element, then the result for all_answers is NONE. Else the calls to the first argument will have produced SOME lst1, SOME lst2,... SOME lstn and the result of all_answers is SOME lst where lst is lst1, lst2,..., lstn appended together (order doesn t matter). Calling all_answers f [] should return SOME []. Hints: Our reference solution is about 10 lines. It uses a helper function with an accumulator and uses @. 4. Write a function match that takes a value * pattern and returns a bindings. Return NONE if the pattern does not match, and return SOME lst where lst is the list of string*value pairs if it does match. Hints: Our reference solution has one case expression with 7 branches. The branch for tuples uses all_answers and ListPair.zip. Our reference solution is about 10 lines. 5. Write a function first_answer of type ( a -> b option) -> a list -> b (notice the 2 arguments are curried). The first argument should be applied to elements of the second argument until the first time it returns SOME v for some v. Then v is the result of the call to first_answer. If the first argument returns NONE for all list elements, then first_answer should raise the exception NoAnswer. Hint: Our reference solution is about 5 lines and doesn t do anything fancy with higher-order functions. 6. Write a function first_match that takes a value * pattern list and returns a bindings. Return NONE if no pattern in the list matches or SOME lst where lst is the list of bindings for the first pattern in the list that matches. Hints: Our reference solution is 3 lines and uses first_answer and a handle expression. The curry function is useful. Part IV: Karma Problem Write a function typecheck_patterns that type checks a pattern list. Types for our pattern language are defined as follows: datatype typ = AnythingT (* can be used as a type for any value *) UnitT (* type for Unit *) IntT (* type for integers *) TupleT of typ list (* type for tuples *) DatatypeT of string (* type for named datatype *) Function typecheck_patterns should have type ((string * string * typ) list) * (pattern list) -> typ option The first argument contains elements that look like ("foo","bar",intt), which means constructor foo makes a value of type DatatypeT "bar" when given a value of type IntT. (In ML, the closest equivalent would be foo : int -> bar.) Assume list elements all have different first fields (the constructor name), but 4

that there many be many elements with the same second field (the datatype name). Under the assumptions this list provides, your function should type-check the pattern list to see if there exists some typ (call it t) that all the patterns in the list can have. If so, return SOME t; otherwise, return NONE. You must return the most lenient type that all the patterns can have. For example, given patterns TupleP[VariableP("x"),VariableP("y")] and TupleP[WildcardP,WildcardP], the most lenient type is TupleT[AnythingT, AnythingT]. (Even though both patterns could both have (e.g.) type TupleT[IntT,IntT], that is not what your function should return.) As another example, given TupleP[WildcardP,WildcardP] and TupleP[WildcardP,TupleP[WildcardP,WildcardP]], return TupleT[AnythingT,TupleT[AnythingT, AnythingT]]. Further Instructions Type Summary. Evaluating a correct homework solution must generate at least the following bindings, in addition to the bindings from the code provided to you: val only_capitals = fn : string list -> string list val longest_string1 = fn : string list -> string val longest_string2 = fn : string list -> string val longest_string_helper = fn : (int * int -> bool) -> string list -> string val longest_string3 = fn : string list -> string val longest_string4 = fn : string list -> string val longest_capitalized = fn : string list -> string val rev_string = fn : string -> string val count_wildcards = fn : pattern -> int val count_wild_and_variable_lengths = fn : pattern -> int val count_some_var = fn : string * pattern -> int val check_pat = fn : pattern -> bool val all_answers = fn : ( a -> b list option) -> a list -> b list option val match = fn : value * pattern -> bindings val first_answer = fn : ( a -> b option) -> a list -> b val first_match = fn : value * pattern list -> bindings Of course, generating those bindings does not guarantee that your solutions are correct... Testing. You are required to test your functions. Put your testing code in a separate file. We will not directly grade it, but you must turn it in. Good test cases might help you get some partial credit if your solution is erroneous. Submission Instructions Submissions that do not adhere to these criteria will lose points: Put all your written solutions to part I in one file, netid hw3written.txt, where netid is your GW NetId. This file must be plain text. We recommend using Emacs to create it. Put all your solution code to parts II and III (and IV, if you do it) in one file, netid hw3.sml Put all the tests you wrote for part II and III (and IV, if you do it) in another file, netid hw3 test.sml. The first line of all three files should be an ML comment with your name, GW NetId, and the phrase Homework 3. Upload all three files to the Homework 3 assignment on BlackBoard. 5

Evaluation Criteria Solutions will be evaluated on correctness with respect to the specifications in this assignment; style, including indentation and line breaks, with respect to the style guide on the course website; elegance, which is an ineffable quality that includes beauty, effectiveness, and simplicity; and adherence to using only those SML features permitted in this homework. 6