На ваш вопрос есть несколько аспектов.
Первое, что я скажу, состоит в том, что комбинация статически типизированного кода с интерпретируемым динамическим временем выполнения наиболее распространена в качестве дополнительного решения для существующего динамического языка. JavaScript, Python и Racket/Scheme/Lisp имеют варианты со статической проверкой типов *. Тем не менее, все они все еще используют среду выполнения исходного языка. Статический тип Проверка дает значение программисту, даже если информация о статическом типе фактически не используется механизмом времени выполнения.
Второй аспект - это то, что, на мой взгляд, может иметь отношение к определению, которое вы указали. Хотя некоторые статические языки отбрасывают информацию о типе при компиляции и используют его только для того, чтобы код не проверял типы, другие, такие как Java и C#, сохраняют информацию о типе вокруг среды выполнения. Что статично статично статично, так это то, что это можно сделать без выполнения кода. Дополнительные проверки могут выполняться во время выполнения (например, в ClassCastException в Java), но это проверка динамического типа (выполняется на основе информации из статически типизированного кода).
Что касается фактического создания интерпретируемой реализации для статически типизированного языка: компиляторы трудны. Не так сложно, как раньше (с ростом LLVM, например), но все же обычно сложнее прототипирования интерпретируемой среды исполнения. Если вы экспериментируете с системами расширенного типа, может быть проще сделать интерпретацию первой реализации. Если он статически проверен на тип, у вас будет отдельная фаза проверки типа без выполнения кода. Это потенциально может заставить среду выполнения не беспокоиться о проверке типов во время фактического выполнения кода.
*: TypeScript, Flow, mypy и Typed Racket Чтобы упомянуть некоторые из них.
Редактировать: Пример, упомянутый в комментарии. Стандартный ML из Нью-Джерси (SML/NJ) является переводчиком для статически типизированного языка Standard ML. Возьмем следующую простую программу:
val _ = print "hello\n";
val foo : string = 4;
В SML/NJ каждое утверждение типа проверяется, а затем оценивается отдельно в существующем типа окружающей среде, прежде чем перейти к следующему утверждению.Таким образом, весь код проверяется по типу перед его выполнением, но вышеуказанная программа все равно будет печатать привет перед сбоем. Следующая программа, однако, ничего не напечатала:
val foo : int = print "hello\n";
Это не печатает привет, а затем пытается запасать ноль в foo. Он не работает до этого, на этапе проверки отдельного типа.
Он по-прежнему обнаруживает ошибки до фактического выполнения какого-либо кода. – melpomene
Вы хотите сказать, что перед началом выполнения первой строки кода выполняется проверка всего типа? Разве это не делается параллельно с исполнением? – zer0uno
Перечитывая свою цитату, я не понимаю, что она пытается сказать. Я думаю, что это просто неправильно. – melpomene