Specifications.Assign04
This assignment is due on Thursday 10/3 by 11:59PM. It include both a programming part and a written part which are to be submitted on Gradescope under assign04 and assign04 (written), respectively.
In order to run the given test suite you have to define every required function in the assignment. We would recommend creating dummy values for each problem when you start if you want to be able to run tests as you work.
Given
s
of type 'a
P
of type 'a -> bool
we say that a function f
of type 'a -> 'a
survives for k
steps with respect to s
and P
if P(f^i(s))
is false for every integer i
satisfying 1 \leq i \leq k
. In logical notation:
\neg P(f(s)) \land \neg P(f(f(s))) \land \dots \land \neg P(f^k(s))
We define \mathsf{lifespan}(f, s, P)
to be the greatest number of steps f
survives with respect to s
and P
. Note that this value may be \infty
.
Given a set of functions F
, we define the last function standing with respect to s
and P
to be
\mathsf{argmax}_{f \in F} \mathsf{lifespan}(f, s, P)
For this problem, we will say that the \mathsf{argmax}
is undefined if there are multiple functions in F
with the same lifespan, or if F
is empty.
Implement the function last_function_standing
so that
last_function_standing funcs start pred
is the last function standing in funcs
with respect to the starting point start
and failing condition pred
. The value should be returned as an option, where the value is None
when funcs
is empty, or there are multiple functions in funcs
with the same finite maximum lifespan. The behavior of the implementation is undefined if funcs
has multiple functions with infinite lifespan.
Put your solution in a file called assign04/lib/assign04_01.ml
. See the file assign04/test/test_suite/test01.ml
for example output behavior.
We're at a point in the course when we can implement our first type checker (technically, we're going to implement a type inference algorithm, but for very simple languages we can implement type checking in terms of type inference). As we've said many times, when we describe a programming language, we need to specify three things: syntax, typing rules and semantics. In this problem, we'll consider a very simple expression language for Boolean values and integers.
We're going to ignore syntax for now (this will come when we start talking about parsing) and instead start with an ADT for expressions in our language (like we did in lecture).
For example, we can represent the expression
if true || false then 3 else 3 + 3
with the value
let e =
IfThenElse
( Or (True, False)
, Num 3
, Add (Num 3, Num 3)
)
(and the process of parsing is exactly the process of getting from the above string to the given value)
We then define our type rules, when means first defining what a type is. For this simple language, every well-typed expression is either an integer or a Boolean value. And for the rules themselves, note that, since there are no variables in this language, there is no need for a context.
\frac {}{\texttt{true} : \texttt{bool}} \qquad \frac {}{\texttt{false} : \texttt{bool}} \qquad \frac {n \text{ is an integer}} {n : \texttt{int}}
\frac{}{}
\frac {e_1 : \texttt{int} \qquad e_2 : \texttt{int} } {e_1 \ \texttt{+} \ e_2 : \texttt{int}} \qquad \frac {e_1 : \texttt{bool} \qquad e_2 : \texttt{bool} } {e_1 \ \texttt{||} \ e_2 : \texttt{bool}}
\frac{}{}
\frac {e_1 : \texttt{bool} \qquad e_2 : \tau \qquad e_3 : \tau } {\texttt{if} \ e_1 \ \texttt{then} \ e_2 \ \texttt{else} \ e_3 : \tau}
Implement a function type_of
where type_of e
is Some t
if t
is the type of e
according to the above rules (i.e., there is a derivation of e
: t
) and None
if e
is not well-typed (i.e., there is no derivation of e
: t
). Try to think about how your implementation implicitly builds a typing derivation, if one exists.
Put your solution in a file called assign04/lib/assign04_02.ml
. See the file assign04/test/test02.ml
for example output behavior. Important: You must include the definitions of expr
and ty
in your solution.
We continue on with the language in the previous problem. The next thing we need is the semantic rules.
\frac{}{\texttt{true} \Downarrow \texttt{true}} \qquad \frac{}{\texttt{false} \Downarrow \texttt{false}} \qquad \frac{n \text{ is a number}}{n \Downarrow n}
\frac{}{}
\frac {e_1 \Downarrow v_1 \qquad e_2 \Downarrow v_2 \qquad v = v_1 + v_2 } {e_1 \ \texttt{+} \ e_2 \Downarrow v} \qquad \frac {e_1 \Downarrow v_1 \qquad e_2 \Downarrow v_2 \qquad v = v_1 \lor v_2 } {e_1 \ \texttt{||} \ e_2 \Downarrow v}
\frac{}{}
\frac {e_1 \Downarrow \texttt{true} \qquad e_2 \Downarrow v_2 } {\texttt{if} \ e_1 \ \texttt{then} \ e_2 \ \texttt{else} \ e_3 \Downarrow v_2} \qquad \frac {e_1 \Downarrow \texttt{false} \qquad e_3 \Downarrow v_3 } {\texttt{if} \ e_1 \ \texttt{then} \ e_2 \ \texttt{else} \ e_3 \Downarrow v_3}
Implement the function eval
so that eval e
is the value of e
according to the above rules (i.e., it's possible to derive e
\Downarrow
eval e
). The behavior of the implementation is undefined if e
is not well-typed (this is one of the benefits of typing).
Put your solution in a file called assign04/lib/assign04_03.ml
. See the file assign04/test/test03.ml
for example output behavior. Important: You should include the line open Assign04_02
so you have access to the type definitions in that file. You must also include the definition of value
in your solution.
Another thing that we've said is that the only reason we maintain a context in our typing derivations is to type expressions with variables. Let's see how this works by re-doing problem 2, but with a language that has variables and let-bindings.
The following ADT for expressions is the same as the one previously defined but with variables and let-bindings. The type ident
is just a synonym for strings, which are used to represent variable names.
We keep the same notion of a type, but introduce a type synonym for contexts, which are association lists that map identifiers to types.
We also rewrite the above typing rules to include contexts, and include rules for variables and let-bindings.
\frac {}{\Gamma \vdash \texttt{true} : \texttt{bool}} \qquad \frac {}{\Gamma \vdash \texttt{false} : \texttt{bool}} \qquad \frac {n \text{ is an integer}} {\Gamma \vdash n : \texttt{int}}
\frac{}{}
\frac {\Gamma \vdash e_1 : \texttt{int} \qquad \Gamma \vdash e_2 : \texttt{int} } {\Gamma \vdash e_1 \ \texttt{+} \ e_2 : \texttt{int}} \qquad \frac {\Gamma \vdash e_1 : \texttt{bool} \qquad \Gamma \vdash e_2 : \texttt{bool} } {\Gamma \vdash e_1 \ \texttt{||} \ e_2 : \texttt{bool}}
\frac{}{}
\frac {\Gamma \vdash e_1 : \texttt{bool} \qquad \Gamma \vdash e_2 : \tau \qquad \Gamma \vdash e_3 : \tau } {\Gamma \vdash \texttt{if} \ e_1 \ \texttt{then} \ e_2 \ \texttt{else} \ e_3 : \tau}
\frac{}{}
\frac {x : \tau \text{ appears in }\Gamma} {\Gamma \vdash x : \tau} \qquad \frac {\Gamma \vdash e_1 : \tau_1 \qquad \Gamma, x : \tau_1 \vdash e_2 : \tau_2 } {\Gamma \vdash \texttt{let} \ x \ \texttt{=} \ e_1 \ \texttt{in} \ e_2 : \tau_2}
Implement a function type_of'
where type_of' gamma e
is Some t
if e
has type t
in the context gamma
(i.e., gamma
\vdash
e
:
t
is derivable) and None
if e
is not well-typed in the context gamma
.
Put your solution in a file called assign04/lib/assign04_04.ml
. See the file assign04/test/test04.ml
for example output behavior. Important: You must include the definitions of expr'
and ty'
in your solution.
The following typing judgment is not derivable.
\cdot \vdash \texttt{let a = let b = 3 in a + b in 2 * a} : \texttt{int}
That said, we can try to construct the "most complete" typing derivation to see where trying to type the given expression fails.
Construct a typing derivation from bottom-up until you reach a judgment of the form \Gamma \vdash x : \tau
which does not follow from the \mathsf{Var}
rule. You final solution should be a valid typing derivation except that one of its axioms (i.e., judgments with no premises) is not valid. Please circle or otherwise mark this invalid judgment.
Write a derivation for the semantic judgment
\left(\texttt{let a = let b = 3 in b + b in 2 * a}\right) \Downarrow \texttt{12}