Infer Generic Return Types
Company: OpenAI
Role: Machine Learning Engineer
Category: Coding & Algorithms
Difficulty: medium
Interview Round: Onsite
Build a small type-inference engine for a toy language. Do not parse raw strings; the input is already constructed as Python objects.
Type model:
- Primitive types: `int`, `float`, `char`, `str`
- Generic type variables: `T1`, `T2`, `T3`, ...
- Tuple types: a node containing a list of child nodes
- Function signatures: a list of parameter types and one output type
Implement the following behavior:
- A `Node` class that can represent either an atomic type or a tuple type
- A `Function` class for function signatures
- String formatting, cloning, and structural equality for types
- `check_and_bind(template, concrete, bindings)`: recursively match a template type against a concrete type
- If the template is a primitive, the concrete type must match exactly
- If the template is a tuple, the concrete type must also be a tuple with the same arity, and children must match recursively
- If the template is a generic such as `T1`, bind it to the concrete type if unbound; otherwise the concrete type must equal the previous binding
- `substitute(node, bindings, require_bound=True)`: replace generic variables with their bindings
- `get_return_type(actual_args, fn)`: check arity, infer bindings from all arguments using one shared binding map, then substitute those bindings into the function's output type
Raise appropriate errors for arity mismatches, primitive mismatches, and conflicting generic bindings.
Example:
- Function `(T1, T2, int, T1) -> (T1, T2)`
- Actual arguments `[int, char, int, int]`
- Returned type should be `(int, char)`
This question tests recursive data structures, unification-style binding, substitution, and precise error handling.
Quick Answer: This question evaluates understanding of type systems, generic unification, recursive data structures, substitution mechanics, and robust error handling in a toy type-inference engine.