SMiLe and Tetris
-
**Due:** 11:00pm Tuesday, April 21 - Checkpoint: 11:00pm Tuesday, April 21: submit one of the two parts
- Due: 11:00pm Tuesday, April 28: full assignment due
- Files:
- fork wellesleycs251 / cs251-tetris, share with bpw
- Programming answers in
smile.sml
,tetris_assignment.rb
- Time estimates in
time.txt
- Submission: commit and push your completed work to your Bitbucket fork.
- Relevant reading:
- SML and Ruby References
- Especially SML notes on evaluation rules for pattern-matching, etc.
- Tools:
- Collaboration:
- All problems fall under the group collaboration policy. You may work with one or zero partners to produce one solution for this assignment. You may discuss ideas with other groups but your group’s writing and code must be due to your group members only.
- Advice:
- Smiling and playing Tetris are both fun. Playing too much Tetris can make the assignment take longer than necessary; smiling too much cannot! :)
1. SMiLe Interpreter [50 points]
In class, we have been building an interpreter for our (currently) dynamically-typed subset of ML (alternately called SMiLe and SortaML). In this assignment, you will answer some questions about the cases we have completed and you will complete the interpreter by finish the last cases of the eval
function: Fun
bindings and the Case
expression, i.e., pattern-matching.
-
Understanding Environments and Closures (Again)
Add English descriptions at each
(* Describe *)
comment insmile.sml
to document precisely what the steps of theFn
andApply
cases do and how they interact with each other. -
Fun
BindingsWe implemented
Val
bindings inLet
expressions together in class. You will add support forFun
bindings.A
Fun(f,x,e)
binding has three pieces: a string giving the name for the function (f
), a string giving the name for the parameter (x
), and anexpr
for the body (e
). Evaluating aFun
binding as part of aLet
expression should produce an environment that extends the current environment with an association off
and a closure for the SMiLe function defined. The closure must support recursion, meaning that the environment it saves must have a mapping fromf
to the closure itself. It is legal for the SMiLe expressionVar f
to appear insidee
, and this must work when an application of the closure is evaluated. (Hint, this is where theref
in the type held byClosureV
becomes important.) See the factorial programs included insmile.sml
for examples.Make sure to document and test your code.
-
Case
ExpressionsImplement
Case
expressions for SMiLe following the semantics ofcase
expressions in ML. ACase
expression carries an expression,e
, to evaluate and match against apattern list
. Thepattern
datatype is given insmile.sml
. Altogether, the whole section ofeval
that handle the SMiLeCase
expression takes about 30 lines of ML code in our sample solution, as a ball-park figure. To accomplish pattern-matching for SMiLe, we added three ML helper functions, and suggest you do similarly:-
match
is a recursive function that checks to see if the evaluated expression’s value matches a single pattern. If the pattern and value match,match
returnsSOME
of a list of(string * value)
pairs representing all the bindings that the pattern introduces. If it does not match,match
returnsNONE
. The implementation uses ML pattern-matching to match simultaneously on a givenpattern
constructor andvalue
constructor.Given a
value
v
andpattern
p
, eitherp
matchesv
or not. If it does, the match produces a list ofstring * value
pairs; order in the list does not matter. Assume that one pattern binds each possible variable at most once. In other words, no pattern will includeVarP "x"
more than once. Make sure to respect this assumption in your test code … or implement a check if you prefer.The rules for matching should be unsurprising:
Wildcard
matches everything and produces the empty list of bindings.VarP s
matches any valuev
and produces the one-element list holding(s,v)
.UnitP
matches onlyUnitV
and produces the empty list of bindings.BoolP false
matches onlyBoolV false
and produces the empty list of bindings (and similarly for other booleans).IntP 17
matches onlyIntV 17
and produces the empty list of bindings (and similarly for other integers).StringP "smile"
matches onlyStringV "smile"
and produces the empty list of bindings (and similarly for other strings).TupleP ps
matches a value of the formTupleV vs
ifps
andvs
have the same length and for alli
, the ith element ofps
matches the ith element ofvs
. The list of bindings produced is all the lists from the nested pattern matches appended together.TagP(s1,p)
matchesTagV(s2,v)
ifs1
ands2
are the same string (you can compare them with=
) andp
matchesv
. The list of bindings produced is the list from the nested pattern match. We call the stringss1
ands2
the constructor name.- Nothing else matches.
tuplematch
is a recursive helper function used when matching tuple patterns recursively inmatch
.evalcase
is a recursive function that iterates through the list of(pattern * expr)
cases given in theCase
expression, applyingmatch
to eachpattern
. For the first pattern that matches,evalcase
then evaluates the associated resultexpr
from the list, using the current environment extended with all the bindings introduced by the pattern. If no pattern matches, raiseNoMatch
.
In addition to implementing the matching code, write SMiLe programs to test it.
-
-
Optional Extension (0 points)
As an optional extension, change
Val
,Fun
andFn
to support arbitrary binding-introducing patterns instead of just a parameter name. This will involve changing the type of arguments to these constructors fromsym
topattern
and using the same pattern-matching code you built forCase
in every function application. -
Optional Challenge (0 points)
As an optional challenge problem, implement basic type-checking for SMiLe:
- Define an ML datatype,
typ
, describing types of SMiLe expressions. Many of its constructors will mirror the constructors of thevalue
datatype. Start without type variables – add those later if you get a simpler type-checker working. Also start without support for type-checking patterns or constructors. If you succeed in type-checking these simpler programs, consider adding explicitDataType
bindings to the SMiLe language, and accompanying support intyp
for datatypes. - Define an ML function,
typecheck : expr -> typ -> bool
, that takes a SMiLe expression and a SMiLe type and checks whether that expression has that type. Follow the type-checking rules we have established for ML. (Again, start without type variables, patterns, or constructors.) Remember, your job here is only to check the given type, not to infer it. (Naturally, to test yourtypecheck
implementation, you will have to manually infer types to pass totypecheck
.)
- Define an ML datatype,
2. Tetris [50 points]
This assignment is adopted from CSE 341 at the University of Washington.
See intructions for installing or using ruby and irb, an interpreter and a REPL for the Ruby language. There is minor configuration to do on tempest
(cs.wellesley.edu
– one line to a configuration file). There are also instructions for installing on your own machine. [Windows instructions may currently include a broken link.]
Please see the PDF tetris instructions, also distributed with the starter code.