Popravdě mám dojem, že se v té teorii typů dost vyžíváte a děláte jí spíš medvědí službu.
Ano, indukční definice typu sudá čísla je pěkná ukázka. A v dalším kódu už pak opravdu můžeme mít jenom krásné garantované sudé číslo a optimalizátor tu informaci může pěkně využít.
Jenže co se stane, když načtete uživatelský vstup a bude tam číslo liché? Nějaký implicitní nebo explicitní parser musí rozhodnout, jestli ta hodnota je v pořádku nebo není a nějak zareagovat. A to je část, co se z ukázek síly funkcionálního programování typicky vypouští.
Vysokoúrovňové informace pro optimalizátor nejsou navíc nezbytně omezeny jen na funkcionální jazyky. Ada a Eiffel mají třeba design by contract (= vstupní podmínky pro parametry), ostatní jazyky budou mít nějaký interface pro next, stream, iterátory nebo cokoliv podobného. (Lazy generátor v Haskellu interně stejně nic jiného nedělá). Dneska s LLVM a LTO se navíc optimalizace často dělají až nad mezikódem.
Pokud se budeme bavit o generických maticích, tak tu informaci o velikosti si to samozřejmě musí nést s sebou, pokud není známá v době překladu. VTable tam být nemusí, protože matice jsou specializovaný případ a stačí číslo. Maximálně, kdyby to bylo tak chytré, že pro některé operace nad specifickými velikostmi použije speciální extrémně optimalizovanou implementaci. Ale opět, v runtime jde o vstup od uživatele, takže tam musí být parser, error handling a nějaký dynamický dispatch.
Pokud by vstupem od uživatele byl samotný typ i s hodnotou (řekněme program "kompot", který správně odpeckuje, pomele, vyrobí etiketu podle počtu a typu vstupního ovoce), tak to interně samozřejmě dynamický dispatch mít bude. Jednoduše pro to, že každé to ovoce (Typ) se zpracovává jinak a náš abstraktní turingův stroj (CPU) neumí nic jiného než skoky dle adres, které si někde přečte.
Procesor s matematickou indukcí ještě nikdo nenapsal a z hlediska strojového kódu to nakonec vždy skončí procedurálně, takže výhoda a nevýhoda těchto jazyků je hlavně ve formální analýze během překladu. Ale ta se dá podpořit i jinak.
Co se typů v Rustu týče, tak borrow checker je move sémantika + escape analysis. Ale lifetime specifier je jednoznačně součást definovaného typu a poskytuje borrow checkeru informace navíc (= něco dle designu musí žít déle než něco jiného). Tuto informaci čistě z kódu neodvodíte, protože algoritmus co tam vývojář napíše, může být z hlediska požadavků typu špatně.
Lifetime pro dokázání správnosti nakládání s pamětí teoreticky nepotřebujete, pokud životnost hlídá jiný mechanizmus jako ref count nebo GC. Ale to má zase runtime implikace.