Можно ли в Erlang определить тип, исключив подтип из супертипа? В качестве примера, как бы я определил тип «что угодно, кроме pid()
»:
-type anything_but_pid() :: ...?
Читая документы по типам данных супервизора, я наткнулся на эту спецификацию типа для child_id()
, которая определяет тип как term()
, а затем говорит Not a pid()
в комментарии ниже:
child_id() = term()
Не
pid()
.
Это лучшее, что я могу сделать, если я не хочу явно перечислять все возможные типы?
В качестве возможного обходного пути вы можете определить спецификацию для своей функции следующим образом:
-spec foo(pid()) -> ...;
(any()) -> ...
foo(data) when is_pid(data) -> error;
foo(data) -> ....
Спасибо! это определенно вариант (по крайней мере, для встроенных типов). предпочтительно, я бы хотел, чтобы Dialyzer перехватывал недопустимые вызовы функций, а не добавлял предложение только для обработки недопустимых входных данных.
Это не сработает, так как такие перегруженные (т. е. состоящие из нескольких пунктов) спецификации не могут иметь перекрывающихся доменов; такие спецификации в настоящее время не поддерживаются и просто игнорируются (предупреждение скопировано прямо из расширения данного примера в небольшой тестовый модуль).
В частности, для anything_but_pid()
вы можете «просто» перечислить все остальные варианты:
-type anything_but_pid() :: port()
| reference()
| atom()
| bitstring()
| number()
| fun()
| maybe_improper_list()
| map()
| tuple()
Конечно, это не обобщает...
Нет, начиная с OTP 23 (и даже 24) это не поддерживается.
Кроме того, ожидать, что Dialyzer поможет в таких случаях, не рекомендуется, поскольку Dialyzer часто преувеличивает по нескольким причинам, и хотя я не думаю, что он сразу же превратит такой тип в term()
, он вполне может это сделать. при первой же возможности (например, везде, где вы вызываете такую функцию).
Действительно. Людям полезно помнить, что Dialyzer — это «типограф успеха», а не строгий типировщик.
BNF для синтаксиса типа можно найти здесь: www2.erlang.se/documentation/doc-8.2/doc/reference_manual/…