Theory test — Chapter 7¶
51 questions; you pass at 80 %. This page shows the questions only: take the test in the terminal, where every answer is graded and explained.
./course quiz 7 # interactive
./course quiz template 7 -o answers/ch07.yaml # or fill in a file ...
./course quiz grade 7 # ... and grade it
unify-mgu · mapping · 1 pt · 01-unificationGive the most general unifier of the single equation
\(h(x, y, g(u)) \doteq h(g(y), g(z), x)\) (\(x, y, z, u\) variables; \(h\) ternary, \(g\) unary)
in solved form: the term bound to each of \(x\), \(y\), \(u\) (the MGU leaves \(z\) unbound).
x, y, ufind-clang-deduction · text · 1 pt · 01-unificationFind where LLVM does it: in clang/lib/Sema/SemaTemplateDeduction.cpp (LLVM 23.1.2),
DeduceTemplateArgumentsByTypeMatch matches a parameter type against an argument type.
When a template parameter has already been deduced with a different value, which
enumerator of TemplateDeductionResult is returned? (Give the enumerator name.)
mm-rule-sequence · sequence · 1 pt · 01-unificationRun Algorithm 7.1.8 (Martelli–Montanari, pop the first equation, decomposed equations go
to the front in order) on the list \(\langle f(x, a) \doteq f(g(y), y),\ g(z) \doteq x \rangle\)
(\(a\) a constant). Give the rules applied, in order (use delete, decompose, conflict,
swap, check, eliminate).
mm-termination-measure · single · 1 pt · 01-unificationWhich quantity strictly decreases under the eliminate rule in the termination proof of
Theorem 7.1.15?
- The total size of the terms in the worklist
- The number of variables occurring in the worklist that are not left-hand sides of the solved part
- The number of equations of the form t = x with t not a variable
- The number of equations in the worklist
uf-unions · number · 1 pt · 01-unificationRun Algorithm 7.1.10 (union-find unification; one node per variable, one per occurrence of an
application; stack of pairs, the first equation's pair popped first) on
\(\{\,f(x, g(x)) \doteq f(g(y), z),\ z \doteq g(g(u))\,\}\). How many union operations are
performed?
find-llvm-equivalence-classes · text · 1 pt · 01-unificationFind where LLVM does it: llvm/include/llvm/ADT/EquivalenceClasses.h (LLVM 23.1.2) is a
union-find. Which member function of EquivalenceClasses merges the classes of two
elements (Algorithm 7.1.10's union)?
occurs-verdict · mapping · 1 pt · 01-unificationFor each single equation, is the verdict ok (a unifier exists), clash or occurs?
- A: \(f(x, y) \doteq f(y, g(x))\)
- B: \(g(x) \doteq h(x, y)\)
- C: \(f(x, a) \doteq f(b, x)\)
- D: \(f(x, g(y)) \doteq f(g(y), x)\)
A, B, C, Doccurs-rectypes · single · 1 pt · 01-unificationocamlc -rectypes -i gives let self_apply = fun x -> x x the type
('a -> 'b as 'a) -> 'b. What does -rectypes change?
- It replaces unification by one-sided matching
- It omits the occurs check and accepts cyclic (rational-tree) solutions
- It generalizes λ-bound variables
- It turns off the value restriction
lambda-vs-let · multi · 1 pt · 02-hindley-milnerWhich MiniML programs are typable in Hindley–Milner (with the builtins of the lab)?
let k = fun x -> fun y -> x in (k 1 true, k true 1)(fun k -> (k 1 true, k true 1)) (fun x -> fun y -> x)fun x -> let y = x in (y 1, y true)let rec len = fun l -> if isnil l then 0 else 1 + len (tail l) in (len (cons 1 nil), len (cons true nil))
principal-type · text · 1 pt · 02-hindley-milnerGive the principal type of fun f -> fun g -> fun x -> g (f x) in the lab's canonical form
(variables 'a, 'b, … in order of first occurrence).
w-unifications · number · 1 pt · 02-hindley-milnerHow many calls of Unify does Algorithm W (Algorithm 7.2.7) make on
let k = fun x -> fun y -> x in (k 1 true, k true 1)?
w-subterm-type · mapping · 1 pt · 02-hindley-milnerAlgorithm W on fun g -> (g 1, g 2 + 1). After inference, what are the (canonical) types of
these subterms? s1 = the whole program, s4 = the first occurrence of g, s6 = g 2 + 1.
s1, s4, s6j-links · single · 1 pt · 02-hindley-milnerWhat does Algorithm J do with the environment Γ after a unification that binds a type
variable occurring in Γ?
- It applies the new substitution to every type in Γ
- Nothing: the variable node is linked in the global union-find, and Γ's types are dereferenced when read
- It re-generalizes every let-bound scheme in Γ
- It copies Γ so that the old version stays valid
w-vs-j-cost · single · 1 pt · 02-hindley-milnerIn the lab's measurement, doubling \(n\) in letChain(n) multiplies W's time by about 4.9 and
J's (with levels) by about 1.6. Which explanation fits?
- W is exponential on let chains, J is linear
- W does Θ(n) work per let (substituting into and scanning the environment), Θ(n²) in total; J with levels does work proportional to each let's type, near-linear in total
- J skips the occurs check
- W unifies more often than J
m-error-position · mapping · 1 pt · 02-hindley-milnerlet g = fun h -> h true in g (fun n -> n + 1) is ill typed. At which position (line:col,
one line, columns from 1) do W, J and M report the error, using the lab's conventions?
W, J, Mm-expected-type · single · 1 pt · 02-hindley-milnerIn Algorithm M, what does the call for the function part of an application e1 e2 receive
as its expected type, when the application itself is expected to have type ρ?
- ρ
- β → ρ for a fresh β, which the argument is then checked against
- a fresh variable, unified with ρ afterwards
- nothing: functions are synthesized
levels-generalize · mapping · 1 pt · 03-generalization-and-complexityAlgorithm J with levels (Algorithm 7.3.2) on
fun a -> let f = fun x -> (a, x) in f. Just after leaving f's right-hand side (current
level back to 1), what are the levels of the type variables of a and of x?
a, xlevels-lowering · single · 1 pt · 03-generalization-and-complexityWhy does binding a variable α to a type t lower the levels of the variables in t to lvl(α)?
- To make instantiation faster
- Because those variables are now reachable from wherever α is: if α is free in the context, so are they, and they must not be generalized by an inner let
- To implement the value restriction
- Because levels must decrease for termination
vr-schemes · mapping · 1 pt · 03-generalization-and-complexityWith the value restriction, how is each let-bound name of
let r = ref nil in let p = (fun x -> x, 1) in let q = fst p in let s = fun z -> get r in (q, s)
bound? Answer generalized (every variable of its type quantified), monomorphic (none) or
partly (some but not all).
r, p, q, svr-unsound · single · 1 pt · 03-generalization-and-complexityWhat goes wrong if let r = ref (fun x -> x) in … is generalized to
∀α. (α → α) ref?
- Inference no longer terminates
- One instance can store an
int -> intfunction and another instance can read it atbool -> bool, so a well-typed program adds 1 totrue - The occurs check fails
- Nothing; the value restriction is only a performance optimization
tower-arrows · number · 1 pt · 03-generalization-and-complexityHow many -> occur in the principal type of pairTower(10) =
let x0 = fun z -> z in let x1 = (x0, x0) in … let x10 = (x9, x9) in x10?
dexptime · single · 1 pt · 03-generalization-and-complexityHM typability is DEXPTIME-complete, yet ML compilers are fast. Which statement reconciles the
two?
- Compilers use approximate inference
- The exponential cases need deep let-nesting that doubles type sizes; with bounded let-depth and type size, inference is nearly linear (McAllester)
- Union-find makes the worst case polynomial
- The value restriction removes the exponential cases
hmx-residual · text · 1 pt · 04-constraint-based-inferenceIn HM(X) with X = type classes, what is the principal (qualified) type of the lab's
fun x -> fun y -> eq x y, with eq : Eq 'a => 'a -> 'a -> bool? (Canonical form.)
hmx-pebble-solution · mapping · 1 pt · 04-constraint-based-inferencePebble's inference mode (pebble-spec §8.9), function body
let a = 2; let b = a * 3; let c = [4, 5]; let d = c[a] + 0.5; let e = 6 << 1; return 0;.
What type does each literal get? (Keys: the literal's value.)
2, 3, 4, 5, 6find-tablegen-inference · text · 1 pt · 04-constraint-based-inferenceFind where LLVM does it: in llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp (LLVM
23.1.2), which TreePattern member function repeatedly applies type constraints to a
pattern's trees until nothing changes?
outsidein-untouchable · single · 1 pt · 04-constraint-based-inferenceIn OutsideIn(X), why may the solver not assign an outer unification variable from inside an
implication a ~ Bool ⊃ p ~ Bool?
- Because unification inside implications is undecidable
- Because the given
a ~ Boolcould make several incomparable assignments valid (p := Bool or p := a), so choosing one would be a guess - Because implications are solved after the program runs
- Because outer variables are rigid
gadt-principal · single · 1 pt · 04-constraint-based-inferenceWhat makes GHC accept test :: Term a -> Bool; test (IsZero t) = True?
- The signature fixes the result type, so the wanted inside the implication is
Bool ~ Bool - GHC defaults p to Bool
- MonoLocalBinds
- The pattern is exhaustive
swift-states · number · 1 pt · 05-swift-constraint-solverIn the lesson's Swift model (+ with overloads (Int,Int)->Int, (Double,Double)->Double,
(String,String)->String; * with the first two; integer literals may be Int or
Double), how many search states (alternatives attempted) does Algorithm 7.5.4 explore for
1 + 2 * 3 with no contextual type, solving the * disjunction first?
swift-family-states · number · 1 pt · 05-swift-constraint-solverThe 3-SAT family of Lesson 7.5 §5 with \(n = 4\) (variables \(x_1, \dots, x_4\); clauses
\((x_4 \vee x_4 \vee x_4)\) and \((\neg x_4 \vee \neg x_4 \vee \neg x_4)\); disjunctions searched in
the order pick_1 … pick_4, clause_1, clause_2): how many states does the search explore?
rust-fallback · mapping · 1 pt · 06-local-and-flow-inferenceIn rustc 1.94, what type does each variable get?
let a = 1; let b: u8 = a; let c = 2; let d = 2.0;
a, c, drust-scope · single · 1 pt · 06-local-and-flow-inferenceWhy does rustc report E0282 for let v = Vec::new(); println!("{}", v.len()); but not for
let c = 2;?
- Vec::new is not generic
- Only integer and float literal variables have a fallback; a general type variable left unresolved at the end of the body is an error
- println! needs the element type
- The body is not an inference scope
kotlin-builder · text · 1 pt · 06-local-and-flow-inferenceKotlin 2.2: what is the type of val xs = buildList { add(1); add(2) }? (Kotlin spelling.)
kotlin-scope · single · 1 pt · 06-local-and-flow-inferenceKotlin 2.2 rejects val n = 1 followed by val d: Double = n, while Pebble's inference mode
accepts the analogous let n = 1; let d: float = n;. Why?
- Kotlin has no integer literal types
- Kotlin's inference scope is the declaration:
n : Intis fixed there; Pebble's is the function body, so the later use decides n - Kotlin defaults to Long
- Pebble has implicit conversions
ts-widening · single · 1 pt · 06-local-and-flow-inferenceIn tsc 6.0, let n = 1; gets the declared type number and const one = 1; the type 1.
Why the difference?
- const declarations are inferred from their uses
- A mutable declaration gets the widened type of its initializer (literal type 1 widened to number), so later assignments of other numbers are allowed; a const keeps the fresh literal type
- number is the default type of numeric literals
- let declarations are flow-typed
ts-evolving · text · 1 pt · 06-local-and-flow-inferencetsc 6.0 with --strict: function late() { let acc = []; acc.push(1); acc.push("s"); return acc; }.
What return type does tsc declare for late? (tsc's spelling.)
pebble-literal-types · single · 1 pt · 06-local-and-flow-inferenceIn Pebble's inference mode, let y = 1.5; let z = y * 2; is accepted. What does Chapter 6's
checker (ch06-typecheck) report for the same lines?
- Nothing: both checkers accept it
- E0402 at the
*: in synthesis mode the literal 2 synthesizes int - E0401 at the literal
- E0416
pebble-e0416 · mapping · 1 pt · 06-local-and-flow-inferencech07-infer on this body (line numbers on the left):
2 let k = 1;
3 let m = k + 2.5;
4 let j: int = k;
5 let w = 3;
6 let t = w == false;
7 let u: bool = 7;
Which error code is reported on each of lines 4, 6 and 7?
4, 6, 7evidence-term · text · 1 pt · 07-type-classes-and-traitsIn the lab's ★ milestone (instances Eq int, Eq bool, Eq 'a => Eq ('a list),
(Eq 'a, Eq 'b) => Eq ('a * 'b) with instance functions eqInt, eqBool, eqList,
eqPair), give the dictionary (evidence term) for Eq ((int * bool) list).
find-rustc-selection · text · 1 pt · 07-type-classes-and-traitsFind it in rustc: which struct in compiler/rustc_trait_selection/src/traits/select/mod.rs
(rustc 1.94.1) has the method select that resolves a trait obligation to an impl?
coherence-overlap · set · 1 pt · 07-type-classes-and-traitsInstance heads of one class C: I1 = C [a], I2 = C [Int], I3 = C (a, Int),
I4 = C (Bool, b), I5 = C Int. Which pairs overlap (write them like I1-I2)?
orphan-rule · multi · 1 pt · 07-type-classes-and-traitsIn crate mine (defining the type Point and the trait Shape), which impls does Rust's
orphan rule allow?
impl std::fmt::Display for Pointimpl Shape for Vec<u8>impl std::fmt::Display for Vec<u8>impl<T> Shape for T
dict-translation · number · 1 pt · 07-type-classes-and-traitsWith NoMonomorphismRestriction, GHC infers x0 :: Eq a => a -> Bool for x0 z = z == z,
and x1 = (x0, x0), x2 = (x1, x1), x3 = (x2, x2). How many dictionary parameters does
x3 take after the dictionary-passing translation?
mono-copies · number · 1 pt · 07-type-classes-and-traitsA Rust program calls the generic fn member<T: PartialEq>(x: &T, xs: &[T]) -> bool as
member(&1i32, …), member(&2u8, …), member(&3i32, …) and member(&"s", …). How many
copies of member (not counting its closures) does monomorphization emit at opt-level 0?
rank-of-type · mapping · 1 pt · 08-higher-rank-and-impredicativityGive the rank (Definition 7.8.1) of each type:
- A:
Int -> Int - B:
forall a. a -> a - C:
(forall a. a -> a) -> Int - D:
((forall a. a -> a) -> Int) -> Bool - E:
Int -> (forall a. a -> a)
A, B, C, D, Erank2-check · multi · 1 pt · 08-higher-rank-and-impredicativityWith both :: (forall a. a -> a) -> (Int, Bool), which calls does GHC 9.4 accept?
both idboth notboth (\x -> x)both (+ 1)
impredicative-instantiation · single · 1 pt · 08-higher-rank-and-impredicativityWith ImpredicativeTypes, how does Quick Look type head ids where ids :: [forall a. a -> a]?
- It generalizes head's result
- It looks at the argument
ids, whose type is known, and instantiates head's type variable with the polymorphic typeforall a. a -> a - It rejects it; impredicative instantiation is never inferred
- It instantiates with a fresh monotype and unifies later
system-f-undecidable · single · 1 pt · 08-higher-rank-and-impredicativityWhy do all practical systems with arbitrary-rank or impredicative polymorphism require some
annotations?
- Because type inference for System F is undecidable (Wells 1999)
- Because unification is NP-hard
- Because of the value restriction
- Because principal types always exist but are too large
blame-first-failure · text · 1 pt · 09-error-localizationWhere (line:col) does Algorithm W report the error in
fun y -> (y + 1, (if y then 2 else 3, y * 4)) (one line, columns from 1)?
mus-count · number · 1 pt · 09-error-localizationHow many minimal unsatisfiable subsets does the labelled constraint set of
fun f -> ((f 1, f 2), f true) have (Algorithm 7.9.4's constraints)?
min-error-source · set · 1 pt · 09-error-localizationFor the same program fun f -> ((f 1, f 2), f true), the two MUSes have the locations
{1:12, 1:14, 1:23, 1:25} and {1:17, 1:19, 1:23, 1:25}. Which locations are, each on its own,
a minimum error source?
provenance-note · single · 1 pt · 09-error-localizationrustc's E0308 for let n = 1; let a: u8 = n; let b: u64 = n; says "expected due to this" at
the u64 annotation. What does Pebble's E0416 note point at for the analogous program?
- The annotation of the second binding
- The use that decided n's type (the checked
ninlet a: int = n) - The declaration of n
- The literal 1