Koine Stage 4 — code comprehension probe

This probe measures how long it takes you to read a small function and predict its output. You will see 10 short functions, half in Python, half in a new language called proto-a v3. Each function is followed by an input; your job is to enter what the function returns for that input.

Total time: ~15 minutes. Each problem has a timer (your time is recorded). There are no negative consequences for wrong answers; this is not a test of your skill, only a measurement of relative comprehension time and correctness.

Before you start, please skim the proto-a v3 spec below.

[show / hide proto-a v3 spec]

# proto-a v3 — minimal spec for code generation

proto-a v3 is an English-base programming language designed for joint readership by humans, machines, and large language models. Use it as you would Python; the differences are surface form, not semantics.

## Statements

- **Imports.** `use X.` for `import X`. `use Y from X.` for `from X import Y`.
- **Function definition.** `binder NAME of ARG1, ARG2:` for `def NAME(ARG1, ARG2):`. With no arguments: `binder NAME:`.
- **Assignment.** `bind X to V.` for `X = V`.
- **Augmented assignment.** `add V to X.` for `X += V`.
- **Return.** `give X.` for `return X`.
- **Print.** `say X.` for `print(X)`.

## Control flow

- **If / elif / else.** `if X then` / `elif X then` / `else:`. Each opens a block; body is indented on the next line.
- **Unless.** `unless X then` is `if not X:` (block opener; body indented).
- **While / until.** `while X:` (Python-style). `until X:` is `while not X:`.
- **For / loop.** `loop X in Y:` for `for X in Y:`. `loop X, Y in Z:` for tuple unpacking. `loop X from A to B:` for `for X in range(A, B + 1):` (inclusive on both ends, ASCENDING only). For descending iteration: `loop X from A down to B:` for `for X in range(A, B - 1, -1):` (inclusive on both ends, DESCENDING).
- **Try / catch.** `try` opens the try block; `catch ERR as e:` for `except ERR as e:`.

## Expressions

- **Equality.** `X is Y` for `X == Y`. `X is not Y` for `X != Y`. `X is none` for `X is None`.
- **Comparisons.** `over` for `>`. `less than` for `<`. `more than` for `>`. Also `<`, `>`, `<=`, `>=`, `==`, `!=` (Python symbols) all valid.
- **Arithmetic.** Use `+`, `-`, `*`, `/`, `%`, `**` (Python symbols).
- **Divisibility predicate.** `divisible X by N` for `(X % N == 0)`. When X is a multi-term expression, parenthesise: `divisible (a + b) by 3`, NOT `divisible a + b by 3`.

## Semantic-density primitives

Use these in place of the longer Python equivalent. They are single-morpheme primitives, denser than the Python idiom they replace.

- `even N` for `(N % 2 == 0)`. Applies to any integer expression that is a simple name, index, or attribute path.
- `odd N` for `(N % 2 != 0)`. Same shape as `even N`.
- `empty L` for `(len(L) == 0)`. Predicate on a sequence-typed name, index, or attribute path.
- `nonempty L` for `(len(L) > 0)`. Predicate on a sequence-typed name.
- `reverse of X` for `X[::-1]`. Works on strings and sequences. Use `reverse of EXPR` where EXPR can be any expression.
- `between A and B for X` for `(A <= X <= B)`. Inclusive on both ends. All three slots accept arbitrary expressions.

## Sequence accessors, reductions, and transforms

These primitives replace common Python sequence idioms with English-prose forms. Each form takes a simple-name or index/attribute/call expression on the right.

- `first of L` for `L[0]`.
- `last of L` for `L[-1]`.
- `length of L` for `len(L)`.
- `sum of L`, `min of L`, `max of L` for `sum(L)`, `min(L)`, `max(L)`.
- `count X in L` for `L.count(X)`. X and L are both expressions.
- `sorted L` for `sorted(L)`.
- `sorted L by F` for `sorted(L, key=F)`.
- `joined L by S` for `S.join(L)`. The separator goes on the `by` side.
- `unique L` for `list(dict.fromkeys(L))` (order-preserving deduplication).

Prefer the primitive over the longer form. For example, `if even n then` is preferred over `if divisible n by 2 then` for integer parity checks. `give reverse of s` is preferred over an explicit index-walk for string reversal. `give first of L` is preferred over `give L[0]` for English readability. `give sorted names by length of` (note: use a function reference, e.g. `len`, not `length of n`) is the natural form.

Limitation. The primitives above operate on simple expression tails (names, indices, attributes, and one-level function calls). They are NOT substituted inside f-strings (`f"...{expr}..."`); if you need a primitive inside an f-string, compute it first with `bind` and reference the variable.
- **Boolean.** `and`, `or`, `not` (Python).
- **Literals.** `none`, `true`, `false` (lowercase, mapped to None, True, False).

## Borrowed from Python verbatim

- Dict literals `{"k": v}`, list literals `[a, b]`, indexed access `X[k]`, attribute access `X.attr`.
- Method calls `obj.method(args)` (Python style).
- f-strings `f"... {X} ..."`.
- List comprehensions `[expr for X in Y if Z]`.
- Lambda `lambda X: Y`.
- Decorators `@decorator`.
- Class definitions `class X(Y): pass`.
- `range(...)`, `len(...)`, `int(...)`, `str(...)`, `isinstance(...)`, etc.

## Style

- One statement per line. Use indentation for blocks (spaces, consistent).
- Multi-line block form preferred. End-of-statement `.` is optional but common.
- No trailing `;`. Use newlines.

## Example: fizzbuzz

```
loop i from 1 to 100:
 if divisible i by 15 then
  say "FizzBuzz".
 elif divisible i by 3 then
  say "Fizz".
 elif divisible i by 5 then
  say "Buzz".
 else:
  say i.
```

## Example: factorial

```
binder factorial of n:
 if n <= 1 then
  give 1.
 else:
  give n * factorial of n - 1.
say factorial of 5.
```

Note: the function-call style `NAME of ARGS` (e.g. `factorial of n - 1`) is the proto-a-native call form. Python-style `NAME(ARGS)` (e.g. `factorial(n - 1)`) is also accepted.

Your name (or initials):