Що таке екзистенційний тип?


171

Я читав статтю у Вікіпедії Екзистенційні типи . Я зрозумів, що їх називають екзистенціальними типами через екзистенціальний оператор (∃). Я не впевнений, в чому справа. Яка різниця між

T = ∃X { X a; int f(X); }

і

T = ∀x { X a; int f(X); }

?


8
Це може бути хорошою темою для programmers.stackexchange.com. programmers.stackexchange.com
jpierson

Відповіді:


192

Коли хтось визначає універсальний тип, ∀Xвони говорять: Ви можете підключати будь-який тип, який ви хочете, мені не потрібно нічого знати про тип, щоб виконувати свою роботу, я буду називати це лише непрозоро якX .

Коли хтось визначає екзистенційний тип, ∃Xвони говорять: я буду тут використовувати будь-який тип; Ви нічого не знаєте про тип, тому можете посилатися на нього лише як непрозореX .

Універсальні типи дозволяють писати такі речі, як:

void copy<T>(List<T> source, List<T> dest) {
   ...
}

copyФункція не має ні найменшого уявлення , що на Tнасправді буде, але це не потрібно.

Екзистенційні типи дозволять писати такі речі:

interface VirtualMachine<B> {
   B compile(String source);
   void run(B bytecode);
}

// Now, if you had a list of VMs you wanted to run on the same input:
void runAllCompilers(List<∃B:VirtualMachine<B>> vms, String source) {
   for (∃B:VirtualMachine<B> vm : vms) {
      B bytecode = vm.compile(source);
      vm.run(bytecode);
   }
}

Кожна реалізація віртуальної машини у списку може мати різний тип байт-коду. runAllCompilersФункція не має ні найменшого уявлення про те , що тип байт - код, але це не потрібно; все, що це робиться - це ретрансляція байт-коду від VirtualMachine.compileдо VirtualMachine.run.

Підстановочні символи типу Java (наприклад:) List<?>є дуже обмеженою формою екзистенціальних типів.

Оновлення: забув зазначити, що ви можете сортувати моделювання екзистенційних типів за допомогою універсальних типів. Спочатку оберніть свій універсальний тип, щоб приховати параметр типу. По-друге, інвертне управління (це ефективно замінює частину "ти" та "я" у наведених вище визначеннях, що є первинною різницею між екзистенціалами та універсаліями).

// A wrapper that hides the type parameter 'B'
interface VMWrapper {
   void unwrap(VMHandler handler);
}

// A callback (control inversion)
interface VMHandler {
   <B> void handle(VirtualMachine<B> vm);
}

Тепер ми можемо мати VMWrapperвласний виклик, VMHandlerякий має універсальну handleфункцію. Чистий ефект той самий, наш код слід сприймати Bяк непрозорий.

void runWithAll(List<VMWrapper> vms, final String input)
{
   for (VMWrapper vm : vms) {
      vm.unwrap(new VMHandler() {
         public <B> void handle(VirtualMachine<B> vm) {
            B bytecode = vm.compile(input);
            vm.run(bytecode);
         }
      });
   }
}

Приклад реалізації VM:

class MyVM implements VirtualMachine<byte[]>, VMWrapper {
   public byte[] compile(String input) {
      return null; // TODO: somehow compile the input
   }
   public void run(byte[] bytecode) {
      // TODO: Somehow evaluate 'bytecode'
   }
   public void unwrap(VMHandler handler) {
      handler.handle(this);
   }
}

12
@Kannan, +1 за дуже корисну, але дещо важку для розуміння відповідь: 1. Я думаю, це допомогло б, якщо ви могли б бути більш чіткими щодо подвійної природи екзистенціальних та універсальних типів. Я лише випадково зрозумів, як ви дуже схоже сформулювали перші два абзаци; лише пізніше ви чітко заявляєте, що обидва визначення в основному однакові, але з "я" і "ви" зворотні. Крім того, я не відразу зрозумів, на що слід позначати "Я" та "Ви".
stakx - більше не вносять внесок

2
(продовження :) 2. Я не повністю розумію значення математичної нотації в List<∃B:VirtualMachine<B>> vmsабо for (∃B:VirtualMachine<B> vm : vms). (Оскільки це узагальнені типи, чи не могли б ви використати ?підстановку Java замість синтаксису "саморобної"?) Я думаю, що це може допомогти мати приклад коду, де не ∃B:VirtualMachine<B>задіяні такі загальні типи, як натомість "прямий" ∃B, тому що загальні типи легко асоціюються з універсальними типами після ваших перших прикладів коду.
stakx - більше не вносяться

2
Раніше я ∃Bчітко говорив про те, де відбувається кількісне визначення. З синтаксисом підстановки визначається кількісний показник ( List<List<?>>насправді означає, ∃T:List<List<T>>а не List<∃T:List<T>>). Також явна кількісна оцінка дозволяє вам посилатися на тип (я змінив приклад, щоб скористатися цим, зберігаючи байт-код типу Bу тимчасовій змінній).
Каннан Гундан

2
Математичні позначення, які використовуються тут, такі ж неохайні, як і пекло, але я не думаю, що це відповідальність (це стандарт). Але все-таки найкраще не зловживати екзистенційними та універсальними кванторами таким чином, можливо ...
Нолдорін

2
@Kannan_Goundan, я хотів би знати, що змушує вас сказати, що підстановки Java - це дуже обмежена версія цього. Чи знаєте ви, що можете реалізувати свою першу прикладну функцію runAllCompilers в чистому Java (з допоміжною функцією для отримання (назви ім’я) параметра wilcard)?
LP_

107

Значення екзистенціального типу типу ∃x. F(x) - пара, що містить певний тип x і значення типу F(x). Тоді як значення поліморфного типу типу ∀x. F(x)- це функція, яка приймає певний тип xі виробляє значення типу F(x). В обох випадках тип закривається над конструктором якогось типуF .

Зауважте, що цей вид перегляду змішує типи та значення. Екзистенційний доказ - це один тип і одне значення. Універсальний доказ - це ціле сімейство значень, індексованих за типом (або відображення від типів до значень).

Отже різниця між вказаними вами двома типами полягає в наступному:

T = ∃X { X a; int f(X); }

Це означає: Значення типу Tмістить тип, який називається X, значення a:Xта функція f:X->int. Виробник значень типу Tзмушує обрати будь-який тип, Xі споживач нічого не може знати про нього X. За винятком того, що є один приклад цього виклику, aі це значення можна перетворити на значення int, передавши його f. Іншими словами, значення типу Tзнає, як створитиint якось . Ну, ми могли б усунути проміжний тип Xі просто сказати:

T = int

Універсально кількісна оцінка дещо відрізняється.

T = ∀X { X a; int f(X); }

Це означає: Значення типу Tможна надати будь-якому типу X, і воно буде виробляти значення a:Xта функцію, f:X->int незалежно від того, що Xце є . Іншими словами: споживач цінностей типу Tможе вибрати будь-який тип X. І виробник значень типу Tвзагалі нічого не може знатиX , але він повинен бути здатний створити значення aдля будь-якого вибору Xі бути здатним перетворити таке значення вint .

Очевидно, що реалізувати цей тип неможливо, оскільки не існує програми, яка могла б створити значення кожного типу, що можна уявити. Якщо ви не допустите безглуздість на кшталтnull знизу

Оскільки екзистенціал є парою, екзистенціальний аргумент може бути перетворений у універсальний за допомогою currying .

(∃b. F(b)) -> Int

те саме, що:

∀b. (F(b) -> Int)

Перший - це ранг-2 екзистенція . Це призводить до наступного корисного властивості:

Кожен екзистенційно кількісно визначений тип рангу n+1- це універсально кількісний тип рангуn .

Існує стандартний алгоритм перетворення екзистенціалів в універсалії, який називається Сколемізація .


7
Можливо, буде корисно (чи ні) згадати Сколемізація en.wikipedia.org/wiki/Skolem_normal_form
Джефф Реді

34

Я думаю, що є сенс пояснювати екзистенційні типи разом із універсальними типами, оскільки ці два поняття є взаємодоповнюючими, тобто одне є «протилежним» іншому.

Я не можу відповісти на кожну деталь про екзистенційні типи (наприклад, дати точне визначення, перерахувати всі можливі варіанти використання, їхнє відношення до абстрактних типів даних тощо), тому що я просто недостатньо обізнаний для цього. Я продемонструю лише (використовуючи 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<α>який представляє вузол у двійковому дереві. Кожен вузол зберігає a 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   |                  
=====================+=====================================

3
Гарне пояснення. Вам не потрібно кидати t.value на Object, ви можете просто посилатися на нього як на Object. Я б сказав, що екзистенційний тип робить метод більш загальним через це. Єдине, що ви можете коли-небудь знати про t.value, це те, що це Об'єкт, тоді як ви могли сказати щось конкретне про α (наприклад, α розширює Serializable).
Крейг П. Мотлін

1
Я тим часом прийшов до висновку , що мій відповідь не на самому ділі пояснити , що екзістенціалах є, і я розглядаю написати ще одне , що більше схоже на перших двох абзацах відповіді Kannan Goudan, який я думаю , що ближче до «істини». Якщо говорити, @Craig: Порівнювати генеричні файли з Objectдосить цікавим: хоча обидва подібні тим, що дають змогу писати код, що не залежить від типу, колишній (generics) не просто відкидає майже всю наявну інформацію про тип досягти цієї мети. У цьому конкретному сенсі дженерики - це засіб проти ObjectІМО.
stakx - більше не вносять внесок

1
@stakx, в цьому коді (від Effective Java) public static void swap(List<?> list, int i, int j) { swapHelper(list, i, j); } private static <E> void swapHelper(List<E> list, int i, int j) { list.set(i, list.set(j, list.get(i))); } , Eце universal typeі ?є existential type?
Кевін Мередіт

Ця відповідь не вірна. ?У типі int height(Tree<?> t)ще не відомо , всередині функції, і по - , як і раніше визначається абонентом , тому що це абонент , який повинен вибрати , яке дерево пройти. Навіть якщо люди називають це екзистенціальний тип в Java, це не так . Запропонований ?заповнювач може бути використаний для реалізації форми екзистенціалів на Java, за деяких обставин, але це не одна з них.
Пітер Хол

15

Це все хороші приклади, але я вирішу відповісти на це дещо інакше. Згадаймо з математики, що ∀x. P (x) означає "для всіх x, я можу довести, що P (x)". Іншими словами, це свого роду функція, ви даєте мені х, і я маю метод довести це для вас.

У теорії типів ми говоримо не про докази, а про типи. Отже, в цьому просторі ми маємо на увазі "для будь-якого типу X, який ви мені даєте, я дам вам конкретний тип P". Тепер, оскільки ми не надаємо Р багато інформації про X, окрім того, що це тип, P не може з цим зробити багато, але є кілька прикладів. P може створити тип «всіх пар одного і того ж типу»: P<X> = Pair<X, X> = (X, X). Або ми можемо створити тип параметра:, P<X> = Option<X> = X | Nilде Nil - тип нульових покажчиків. Ми можемо скласти список з нього: List<X> = (X, List<X>) | Nil. Зауважте, що останній є рекурсивним, значення - List<X>це або пари, де перший елемент є X, а другий - aList<X> або він є нульовим покажчиком.

Тепер, з математики ∃x. P (x) означає "я можу довести, що існує певна х така, що P (x) істинна". Таких х може бути багато, але щоб довести це, одного достатньо. Ще один спосіб подумати над цим - це те, що повинен існувати не порожній набір пар доказів і доказів {(x, P (x))}.

У перекладі на теорію типів: Тип у сім'ї ∃X.P<X>- це тип X і відповідний тип P<X>. Зауважте, що до того, як ми дали X Р, (щоб ми знали все про X, але P дуже мало), зараз все навпаки.P<X>не обіцяє давати будь-яку інформацію про X, тільки що вона є, і що вона справді є типом.

Чим це корисно? Ну, P може бути типом, який має спосіб викрити свій внутрішній тип X. Прикладом може бути об'єкт, який приховує внутрішнє уявлення про його стан X. Хоча ми не маємо можливості безпосередньо маніпулювати ним, ми можемо спостерігати його вплив шляхом тикатися на P. Можливо, існує багато реалізацій цього типу, але ви можете використовувати всі ці типи, незалежно від того, який з них було обрано.


2
Хм, але що функція отримує, знаючи, що це P<X>замість P(такий же функціонал і тип контейнера, скажімо, але ви не знаєте, що він містить X)?
Клавдіу

3
Строго кажучи, ∀x. P(x)нічого не означає про доказовість P(x), лише правду.
R .. GitHub СТОП ДОПОМОГА ICE

11

Щоб безпосередньо відповісти на ваше запитання:

У універсальному типі використання Tмає включати параметр типу X. Наприклад T<String>або T<Integer>. Для екзистенціальних типів використання Tне включає цей параметр типу, оскільки він невідомий або не має значення - просто використовуйте T(або на JavaT<?> ).

Додаткова інформація:

Універсальні / абстрактні типи та екзистенційні типи - це подвійність перспективи між споживачем / клієнтом об'єкта / функції та виробником / реалізацією його. Коли одна сторона бачить універсальний тип, інша бачить екзистенційний тип.

У Java ви можете визначити загальний клас:

public class MyClass<T> {
   // T is existential in here
   T whatever; 
   public MyClass(T w) { this.whatever = w; }

   public static MyClass<?> secretMessage() { return new MyClass("bazzlebleeb"); }
}

// T is universal from out here
MyClass<String> mc1 = new MyClass("foo");
MyClass<Integer> mc2 = new MyClass(123);
MyClass<?> mc3 = MyClass.secretMessage();
  • З точки зору клієнта з MyClass, Tє універсальним , так як ви можете замінити будь-який тип дляT коли ви використовуєте цей клас , і ви повинні знати фактичний тип T щоразу , коли ви використовуєте примірникMyClass
  • З погляду самих методів MyClass,T є екзистенціальним, оскільки не знає реального типуT
  • У Java ?представляє екзистенціальний тип - таким чином, коли ви знаходитесь всередині класу, Tце в основному ?. Якщо ви хочете обробити екземпляр MyClassз Tекзистенційним, ви можете оголосити , MyClass<?>як в secretMessage()наведеному вище прикладі.

Екзистенційні типи іноді використовуються для приховування деталей реалізації чогось, про що йшлося в інших місцях. Версія Java на це може виглядати так:

public class ToDraw<T> {
    T obj;
    Function<Pair<T,Graphics>, Void> draw;
    ToDraw(T obj, Function<Pair<T,Graphics>, Void>
    static void draw(ToDraw<?> d, Graphics g) { d.draw.apply(new Pair(d.obj, g)); }
}

// Now you can put these in a list and draw them like so:
List<ToDraw<?>> drawList = ... ;
for(td in drawList) ToDraw.draw(td);

Зробити це належним чином досить складно, тому що я прикидаюся якоюсь функціональною мовою програмування, якою Java не є. Але справа в тому, що ви фіксуєте певний стан плюс список функцій, які працюють на цьому стані, і ви не знаєте реального типу частини стану, але функції роблять, оскільки вони вже були узгоджені з цим типом .

Зараз у Java всі нефінальні непомітивні типи частково існують. Це може здатися дивним, але тому, що змінна, оголошена якою, Objectпотенційно може бути підкласомObject замість цього, ви не можете оголосити конкретний тип, лише "цей тип або підклас". Таким чином, об'єкти представлені як біт стану плюс список функцій, які працюють на цьому стані - саме ту функцію, яку потрібно викликати, визначається під час виконання при пошуку. Це дуже схоже на використання екзистенціальних типів вище, де у вас є частина екзистенційного стану та функція, яка працює на цьому стані.

У статично типізованих мовах програмування без підтипів і запитів екзистенціальні типи дозволяють керувати списками об'єктів, що відрізняються типом. Список T<Int>не може містити T<Long>. Однак, список T<?>може містити будь-які варіації T, дозволяючи помістити в список багато різних типів даних та перетворити їх у цілий int (або виконувати будь-які операції, що надаються всередині структури даних) на вимогу.

Можна майже завжди перетворювати запис із екзистенційним типом у запис, не використовуючи закриття. Закриття також екзистенційно набирається тим, що вільні змінні, над якими він закритий, приховані від абонента. Таким чином, мова, яка підтримує закриття, але не екзистенційні типи, може дозволити вам робити закриття, що мають той самий прихований стан, який ви б помістили в екзистенційну частину об'єкта.


11

Екзистенційний тип - непрозорий тип.

Придумайте ручку файлу в Unix. Ви знаєте, що його тип є int, тому ви можете легко підробити його. Наприклад, ви можете спробувати прочитати з ручки 43. Якщо так сталося, що програма відкрила файл із цією конкретною ручкою, ви прочитаєте з неї. Ваш код не повинен бути шкідливим, просто неохайним (наприклад, ручка може бути неініціалізованою змінною).

Екзистенційний тип прихований від вашої програми. Якщо fopenповернено екзистенціальний тип, все, що ви можете зробити з ним, це використовувати його з деякими бібліотечними функціями, які приймають цей екзистенційний тип. Наприклад, складається наступний псевдо-код:

let exfile = fopen("foo.txt"); // No type for exfile!
read(exfile, buf, size);

Інтерфейс "прочитати" оголошується як:

Існує тип T такий, що:

size_t read(T exfile, char* buf, size_t size);

Файл змінної не є int, не a char*, не структура. Файл - нічого, що ви можете виразити в системі типів. Ви не можете оголосити змінну, тип якої невідомий, і ви не можете запустити, скажімо, вказівник на цей невідомий тип. Мова вам не дозволить.


9
Це не спрацює. Якщо підпис readє, ∃T.read(T file, ...)то ви нічого не можете передати як перший параметр. Що б спрацювало - це fopenповернути ручку файлу та функцію читання, виконану за допомогою того ж екзистенціалу :∃T.(T, read(T file, ...))
Каннан Гундан

2
Це, здається, просто говорить про АДТ.
kizzx2

7

Здається, я заходжу трохи пізно, але все одно, цей документ додає ще один погляд на те, що існують екзистенційні типи, хоча це не конкретно мовно-агностичний характер, тоді слід бути досить простішим для розуміння екзистенціальних типів: http: //www.cs.uu .nl / групи / ST / Проекти / ehc / ehc-book.pdf (глава 8)

Різниця між універсальним і екзистенційно кількісно визначеним типом можна охарактеризувати наступним спостереженням:

  • Використання значення з ∀ кількісно визначеним типом визначає тип для вибору для встановлення кількісної змінної типу. Наприклад, виклик функції ідентичності "id :: ∀aa → a" визначає тип, який слід вибрати для змінної типу a для цього конкретного додатка id. Для додатка функції “id 3” цей тип дорівнює Int.

  • Створення значення з ∃ кількісно визначеним типом визначає та приховує тип кількісної змінної типу. Наприклад, творець "∃a. (A, a → Int)", можливо, сконструював значення цього типу з "(3, λx → x)"; інший творець сконструював значення з тим самим типом з "('x', λx → ord x)". З точки зору користувачів, обидва значення мають один і той же тип і, таким чином, взаємозамінні. Значення має певний тип, обраний для змінної типу a, але ми не знаємо, який тип, тому цю інформацію більше не можна використовувати. Інформація про тип цього значення була "забута"; ми лише знаємо, що вона існує.


1
Хоча це посилання може відповісти на питання, краще включити сюди суттєві частини відповіді та надати посилання для довідки. Відповіді лише на посилання можуть стати недійсними, якщо пов’язана сторінка зміниться.
sheilak

1
@sheilak: оновив відповідь, дякую за пропозицію
themarketka

5

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

Наприклад, у Scala одним із способів виразити екзистенціальний тип є абстрактний тип, обмежений деякими верхніми або нижніми межами.

trait Existential {
  type Parameter <: Interface
}

Еквівалентно обмежений універсальний тип - це екзистенційний тип, як у наступному прикладі.

trait Existential[Parameter <: Interface]

Будь-який веб-сайт може використовувати, Interfaceтому що будь-який миттєвий підтип Existentialповинен визначати, type Parameterякий повинен реалізувати Interface.

Вироджений випадок екзистенціального типу в Scala є абстрактним типом , який ніколи не згадується і , отже , не повинно бути визначено будь-яким підтипом. Це фактично має скорочене позначення List[_] у Scala та List<?>на Java.

Мою відповідь надихнула пропозиція Мартіна Одерського щодо уніфікації абстрактних та екзистенційних типів. Супроводжуючий слайд допомагає розумінню.


1
Ознайомившись з вищенаведеним матеріалом, здається, ви добре підсумували моє розуміння: Універсальні типи, ∀x.f(x)непрозорі для своїх функцій прийому, а Екзистенціальні типи, ∃x.f(x)обмежуються певними властивостями. Зазвичай всі параметри є екзистенціальними, оскільки їх функція буде маніпулювати ними безпосередньо; однак загальні параметри можуть мати типи, які є універсальними, оскільки функція не буде керувати ними за межами основних універсальних операцій, таких як отримання посилання, як у:∀x.∃array.copy(src:array[x] dst:array[x]){...}
Джордж

Як описано тут, члени типу stackoverflow.com/a/19413755/3195266 можуть імітувати універсальне кількісне визначення за допомогою типу ідентичності. І напевно, існує forSomeтипова кількісна оцінка параметрів типу.
Нетсу

3

Дослідження абстрактних типів даних та приховування інформації принесло екзистенційні типи в мови програмування. Здійснення абстрактного типу даних приховує інформацію про цей тип, тому клієнт цього типу не може його зловживати. Скажімо, у вас є посилання на об'єкт ... деякі мови дозволяють передати це посилання на посилання на байти і робити все, що вам потрібно, на цю частину пам'яті. З метою гарантування поведінки програми корисно, щоб мова примушувала вас діяти лише посиланням на об'єкт лише методами, передбаченими дизайнером об'єкта. Ви знаєте, що тип існує, але більше нічого.

Побачити:

Абстрактні типи мають екзистенційний тип, МІТЧЕЛЬ І ПЛОТКІН

http://theory.stanford.edu/~jcm/papers/mitch-plotkin-88.pdf


1

Я створив цю діаграму. Я не знаю, чи це жорстко. Але якщо це допоможе, я радий. введіть тут опис зображення


-6

Як я розумію, це математичний спосіб описати інтерфейси / абстрактний клас.

Що стосується T = ∃X {X a; int f (X); }

Для C # це перекладається на загальний абстрактний тип:

abstract class MyType<T>{
    private T a;

    public abstract int f(T x);
}

"Екзистенціальне" просто означає, що існує певний тип, який підкоряється визначеним тут правилам.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.