Как избежать создания специальной системы типов на языках с динамической типизацией? - PullRequest
19 голосов
/ 16 декабря 2010

В каждом проекте, который я начал на языках без систем типов, я в конечном итоге начинаю изобретать систему типов во время выполнения.Может быть, термин «система типов» слишком силен;по крайней мере, я создаю набор валидаторов типа / диапазона значений, когда я работаю со сложными типами данных, и затем я чувствую необходимость быть параноиком относительно того, где типы данных могут быть созданы и изменены.

Я не думал дважды об этом до сих пор.Как независимый разработчик, мои методы работали на практике над несколькими небольшими проектами, и нет никаких причин, по которым они перестали бы работать сейчас.

Тем не менее, это должно быть неправильно.Мне кажется, что я не использую динамически типизированные языки "правильно".Если я должен изобрести систему типов и применить ее сам, я также могу использовать язык с типами для начала.

Итак, мои вопросы:

  • Существуют ли ужепарадигмы программирования (для языков без типов), которые исключают необходимость использования или изобретения систем типов?
  • Существуют ли иные общие рекомендации о том, как решать проблемы, которые статическая типизация решает в языках с динамической типизацией (без злобного переизобретения типов)?

Вот конкретный пример для рассмотрения.Я работаю с датами и часовыми поясами в эрланге (динамический, строго типизированный язык).Это общий тип данных, с которым я работаю:

{{Y,M,D},{tztime, {time, HH,MM,SS}, Flag}}

... где {Y,M,D} - кортеж, представляющий действительную дату (все записи являются целыми числами), tztime и time - атомы, HH,MM,SS являются целыми числами, представляющими нормальное 24-часовое время, а Flag является одним из атомов u,d,z,s,w.

Этот тип данных обычно анализируется из входных данных, поэтому для обеспечения правильного ввода и правильного синтаксического анализатора,значения должны быть проверены на правильность типа и допустимые диапазоны.Позже, экземпляры этого типа данных сравниваются друг с другом, делая тип их значений тем более важным, поскольку все термины сравниваются.Из справочника erlang

number < atom < reference < fun < port < pid < tuple < list < bit string

Ответы [ 5 ]

7 голосов
/ 16 декабря 2010

Помимо смешения статической и динамической и сильной и слабой типизации:

То, что вы хотите реализовать в своем примере, на самом деле не решается большинством существующих систем статической типизации.Проверки диапазона и такие сложности, как 31 февраля и особенно анализируемый ввод, обычно проверяются во время выполнения, независимо от того, какая у вас система типов.

Ваш пример в Erlang У меня есть несколько рекомендаций:

  • Использовать записи.Помимо того, что он полезен и полезен по целому ряду причин, он позволяет легко проверять типы во время выполнения без особых усилий, например:

    is_same_day(#datetime{year=Y1, month=M1, day=D1}, 
                #datetime{year=Y2, month=M2, day=D2}) -> ...
    

    Без усилий сопоставляет только две записи даты и времени.Вы даже можете добавить охранников для проверки диапазонов, если источник не заслуживает доверия.И он соответствует эрлангам, позволяющим сбить метод обработки ошибок: если совпадение не найдено, вы получаете несоответствие и можете обработать это на уровне, где это уместно (обычно на уровне супервизора).

  • Как правило, пишите свой код, чтобы он вылетал, когда предположения не действительны

  • Если это не выглядит достаточно статично, проверьте: используйте typer и dialyzer, чтобы найти типошибок, которые могут быть обнаружены статически, все, что осталось, будет проверено во время выполнения.

  • Не будьте слишком строгими в своих функциях, какие «типы» вы принимаете, иногда добавленная функциональность простоделать что-то полезное даже для разных входов стоит больше, чем проверка типов и диапазонов в каждой функции.Если вы делаете это там, где это обычно имеет значение, вы обнаружите ошибку достаточно рано, чтобы ее можно было легко исправить.Это особенно верно для функционального языка, где вы всегда знаете, откуда происходит каждое значение.

3 голосов
/ 16 декабря 2010

Много хороших ответов, позвольте мне добавить:

Существуют ли существующие парадигмы программирования (для языков без типов), которые исключают необходимость использования или изобретения систем типов?

Самая важная парадигма, особенно в Erlang, такова: предположим, что тип верен, иначе допустим крах.Не пишите чрезмерно проверяющий параноидальный код, но предположите, что полученный вами ввод имеет правильный тип или правильный шаблон.Не пишите (есть исключения из этого правила, но в целом)

foo({tag, ...}) -> do_something(..);
foo({tag2, ...}) -> do_something_else(..);
foo(Otherwise)  ->
    report_error(Otherwise),
    try to fix problem here...

Убейте последнее предложение и сразу выведите его из строя.Позвольте супервизору и другим процессам выполнить очистку (вы можете использовать monitors() для вспомогательных процессов, чтобы узнать, когда произошел сбой).

Будьте точны, однако, .Напишите

bar(N) when is_integer(N) -> ...

baz([]) -> ...
baz(L) when is_list(L) -> ...

, если известно, что функция работает только с целыми числами или списками соответственно.Да, это проверка во время выполнения, но цель - передать информацию программисту.Кроме того, HiPE, как правило, используют подсказку для оптимизации и, по возможности, исключают проверку типов.Следовательно, цена может быть меньше, чем вы думаете.

Вы выбираете нетипизированный / динамически типизированный язык, поэтому цена, которую вы должны заплатить, заключается в том, что проверка типов и ошибки в конфликтах будут происходить во время выполнения.Как подсказывают другие посты, статически типизированный язык также не освобождается от некоторых проверок - система типов (обычно) является приближением доказательства правильности.В большинстве статических языков вы часто получаете информацию, которой вы не можете доверять.Этот вход преобразуется на «границе» приложения, а затем преобразуется во внутренний формат.Преобразование служит для обозначения доверия: с этого момента вещь была проверена, и мы можем предположить определенные вещи об этом.Сила и правильность этого предположения напрямую связаны с его сигнатурой типа и тем, насколько хорош программист в манипулировании статическими типами языка.

Существуют ли в других случаях общие рекомендации о том, как решать проблемы,статическая типизация решает в динамически типизированных языках (без злобного переизобретения типов)?

У Эрланга есть dialyzer, который можно использовать для статического анализа и вывода типов ваших программ.Он не будет вызывать столько ошибок типа, как проверка типов, например, в Ocaml, но он также не будет "плакать волком": ошибка диализатора, несомненно, является ошибкой в ​​программе.И это не будет отклонять программу, которая может работать нормально.Простой пример:

and(true, true) -> true;
and(true, _)    -> false;
and(false, _)   -> false.

Вызов and(true, greatmistake) вернет false, но статическая система типов отклонит программу, потому что из первой строки будет выводить, что сигнатура типа принимает логическое значение () значение как 2-й параметр.Диализатор, напротив, примет эту функцию и даст ей подпись (boolean (), term ()) -> boolean ().Это можно сделать, потому что нет необходимости защищать a priori от ошибки.Если есть ошибка, во время выполнения система проверит проверку типа, которая ее перехватит.

2 голосов
/ 16 декабря 2010

Для того, чтобы статически типизированный язык соответствовал гибкости динамически типизированного, я думаю, что ему понадобится много, возможно, бесконечно много функций.

В мире Хаскелла каждый слышит много изощренной, иногда до такой степени страшной, терминологии. Типы занятий. Параметрический полиморфизм. Обобщенные алгебраические типы данных. Тип семьи. Функциональные зависимости. Язык программирования Ωmega продвигает его еще дальше, в том числе на веб-сайте, в котором перечислены "функции уровня типа" и "уровень полиморфизма".

Что все это значит? Функции, добавленные в статическую типизацию, делают ее более гибкой. Эти функции могут быть действительно классными, элегантными и умопомрачительными, но зачастую их трудно понять. За исключением кривой обучения, системы типов часто не могут элегантно моделировать реальные проблемы. Особенно хорошим примером этого является взаимодействие с другими языками (основной мотив для C # 4 dynamic функция ).

Языки с динамической типизацией дают вам возможность реализовать собственную структуру правил и предположений о данных, а не ограничиваться постоянно ограниченной системой статических типов. Однако «ваша собственная структура» не будет проверяться машиной, а это означает, что вы обязаны убедиться, что ваша «система типов» безопасна и ваш код хорошо «типизирован».

Одна вещь, которую я узнал из изучения Хаскелла, заключается в том, что я могу перенести извлеченные уроки, касающиеся строгой типизации и логических рассуждений, на языки со слабой типизацией, такие как C и даже ассемблер, и сам выполнять «проверку типов». А именно, я могу доказать, что разделы кода правильны сами по себе, учитывая правила, которым должны следовать мои функции и значения, и предположения, которые мне разрешено делать в отношении других функций и значений. При отладке я снова проверяю вещи и думаю, обоснован ли мой подход.

Суть: динамическая печать дает вам больше гибкости . С другой стороны, языки со статической типизацией имеют тенденцию быть более эффективными (на порядок), а хорошие системы со статическим типом значительно сокращают время отладки, позволяя компьютеру делать большую часть работы за вас. Если вы хотите получить преимущества обоих, установите в своем мозгу средство проверки статического типа , изучая приличные языки со строгим шрифтом.

1 голос
/ 16 декабря 2010

Статически типизированный язык обнаруживает ошибки типа во время компиляции. Динамически типизированный язык обнаруживает их во время выполнения. Существуют некоторые скромные ограничения на то, что можно писать на статически типизированном языке, так что все ошибки типов могут быть обнаружены во время компиляции.

Но да, у вас все еще есть типы даже в динамически типизированном языке, и это хорошо. Проблема заключается в том, что вы выполняете множество проверок во время выполнения, чтобы убедиться, что у вас есть типы, которые вы думаете , которые вы делаете, поскольку компилятор об этом не позаботился.

В Erlang есть очень хороший инструмент для определения и статической проверки большого количества типов - диализатор: Система типов Эрланга , для ссылок.

Так что не изобретайте типы заново, используйте инструменты ввода, которые уже предоставляет Erlang, для обработки типов, которые уже существуют в вашей программе (но которые вы еще не указали).

И это само по себе, к сожалению, не устранит проверки диапазона. Без большого количества специального соуса вам действительно придется применять его самостоятельно по соглашению (и умные конструкторы и т. Д., Чтобы помочь), или возвращаться к проверкам во время выполнения, или к обоим.

1 голос
/ 16 декабря 2010

Иногда данные нуждаются в проверке.Проверка любых данных, полученных из сети, - почти всегда хорошая идея, особенно данные из общедоступной сети.Быть параноиком здесь только хорошо.Если что-то, напоминающее статическую систему типов, помогает этому наименее болезненным образом, пусть будет так.Есть причина, почему Erlang допускает аннотации типов.Даже сопоставление с образцом можно рассматривать как просто вид динамической проверки типов;тем не менее, это центральная особенность языка.Сама структура данных в Erlang - это «тип».

Хорошо, что вы можете настроить свою «систему типов» под свои нужды, сделать ее гибкой и умной, в то время как системы типов для ОО-языковкак правило, имеют фиксированные функции.Когда используемые вами структуры данных являются неизменяемыми, после проверки такой структуры можно с уверенностью предположить, что она соответствует вашим ограничениям, как при статической типизации.

Нет смысла быть готовым к обработке любых данных в любой точке программы, с динамической типизацией или без нее.«Динамический тип» - это, по сути, объединение всех возможных типов;ограничение его полезным подмножеством является допустимым способом программирования.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...