Я думаю, что есть смысл объяснять экзистенциальные типы вместе с универсальными типами, поскольку эти два понятия дополняют друг друга, то есть одно является «противоположным» другому.
Я не могу ответить на все подробности о экзистенциальных типах (например, дать точное определение, перечислить все возможные варианты использования, их отношение к абстрактным типам данных и т. Д.), Потому что я просто недостаточно осведомлен для этого. Я продемонстрирую (используя Java) только то, что эта статья HaskellWiki называет основной эффект экзистенциальных типов:
Экзистенциальные типы можно использовать для разных целей. Но они делают «скрывают» переменную типа с правой стороны. Обычно любая переменная типа, отображаемая справа, также должна отображаться слева […]
Пример настройки:
Следующий псевдокод не совсем корректный Java, хотя это было бы достаточно легко исправить. Собственно, это именно то, что я собираюсь сделать в этом ответе!
class Tree<α>
{
α value;
Tree<α> left;
Tree<α> right;
}
int height(Tree<α> t)
{
return (t != null) ? 1 + max( height(t.left), height(t.right) )
: 0;
}
Позвольте мне вкратце пояснить это для вас. Мы определяем
рекурсивный тип Tree<α>
, который представляет узел в двоичном дереве. Каждый узел хранит value
некоторого типа α и имеет ссылки на необязательные поддеревья left
и right
того же типа.
функция height
, которая возвращает наибольшее расстояние от любого листового узла до корневого узла t
.
Теперь давайте превратим приведенный выше псевдокод для height
в правильный синтаксис Java! (Я буду опускать некоторые шаблоны для краткости, такие как модификаторы объектной ориентации и доступности.) Я собираюсь показать два возможных решения.
1. Решение универсального типа:
Наиболее очевидное исправление - просто сделать height
универсальным, добавив параметр типа α в его сигнатуру:
<α> int height(Tree<α> t)
{
return (t != null) ? 1 + max( height(t.left), height(t.right) )
: 0;
}
Это позволит вам объявлять переменные и создавать выражения типа α внутри этой функции, если вы хотите. Но...
2. Решение экзистенциального типа:
Если вы посмотрите на тело нашего метода, вы заметите, что на самом деле мы не получаем доступ и не работаем с чем-либо типа α! Нет ни выражений с этим типом, ни каких-либо переменных, объявленных с этим типом ... Итак, почему мы вообще должны делать height
универсальным? Почему мы не можем просто забыть о α? Как оказалось, мы можем:
int height(Tree<?> t)
{
return (t != null) ? 1 + max( height(t.left), height(t.right) )
: 0;
}
Как я писал в самом начале этого ответа, экзистенциальный и универсальный типы дополняют / двойственны по своей природе. Таким образом, если решение универсального типа заключалось в том, чтобы сделать height
более универсальным, тогда мы должны ожидать, что экзистенциальные типы будут иметь противоположный эффект: сделать его менее универсальным, а именно путем скрытия / удаления параметр типа α.
Как следствие, вы больше не можете ссылаться на тип t.value
в этом методе или манипулировать какими-либо выражениями этого типа, потому что к нему не привязан идентификатор. (?
подстановочный знак - это специальный токен, а не идентификатор, который "фиксирует "тип.) t.value
фактически стал непрозрачным; возможно, единственное, что вы можете с ним сделать, - это привести его к Object
.
Резюме:
===========================================================
| universally existentially
| quantified type quantified type
---------------------+-------------------------------------
calling method |
needs to know | yes no
the type argument |
---------------------+-------------------------------------
called method |
can use / refer to | yes no
the type argument |
=====================+=====================================
person
stakx - no longer contributing
schedule
31.12.2011