실존 유형은 무엇입니까?


171

Wikipedia 기사 Existential types를 읽었습니다 . 나는 실재 연산자 (∃) 때문에 실재 유형이라고 불렀습니다. 그래도 그 요점이 무엇인지 잘 모르겠습니다. 차이점은 무엇입니까

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<?>는 매우 제한된 형태의 실존 유형입니다.

업데이트 : 범용 유형으로 실존 유형을 시뮬레이션 할 수 있다는 것을 언급하지 않았습니다. 먼저 유니버설 유형을 래핑하여 유형 매개 변수를 숨 깁니다. 둘째, 인버트 제어 (이것은 위의 정의에서 "당신"과 "I"부분을 효과적으로 교환합니다. 이는 실존과 유니버설의 주요 차이점입니다).

// 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우리 자신 의 전화 를 가질 수 있습니다 . 순 효과는 동일합니다. 코드는 불투명 으로 처리 해야합니다.VMHandlerhandleB

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. 실존적이고 보편적 인 유형의 이중 특성에 대해 더 명확하게 설명하면 도움이 될 것이라고 생각합니다. 나는 처음 두 단락을 매우 유사하게 표현한 것을 우연히 깨달았습니다. 나중에 두 정의가 기본적으로 동일하지만 "I"와 "you"가 반대로되어 있음을 명시 적으로 언급해야합니다. 또한, 나는 "나"와 "당신"이 무엇을 의미하는지 즉시 이해하지 못했습니다.
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변수 에 유형의 바이트 코드를 저장하여이를 활용하도록 예제를 수정했습니다 ).
Kannan Goundan

2
여기에 사용 된 수학적 표기법은 지옥만큼 엉성하지만 응답자의 잘못이라고 생각하지 않습니다 (표준). 아직도, 그런 식으로 실존적이고 보편적 인 정량자를 남용하지 않는 것이 가장 좋습니다.
Noldorin

2
@ Kananna_Goundan, Java 와일드 카드가 이것의 매우 제한된 버전이라고 말하는 이유를 알고 싶습니다. 순수한 Java로 첫 번째 runAllCompilers 예제 함수를 구현할 수 있다는 것을 알고 있습니까 (도움말 함수를 사용하여 wilcard 매개 변수 검색).
LP_

107

실존 형 등이 ∃x. F(x) 한 쌍의 일부 함유 유형 x 유형을 F(x). 같은 다형성 형태의 값 반면 ∀x. F(x)A는 함수 몇몇 형식을 사용 x하고 생산 타입의 값 F(x). 두 경우 모두 형식은 일부 형식 생성자 위로 닫힙니다 F.

이보기는 유형과 값을 혼합합니다. 실존 증명은 하나의 유형과 하나의 값입니다. 범용 증명은 유형별로 인덱싱 된 전체 값 계열 (또는 유형에서 값으로의 매핑)입니다.

따라서 지정한 두 유형의 차이점은 다음과 같습니다.

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

의미 : type의 값은 , value 및 function T이라는 유형을 포함 합니다 . 유형의 값의 프로듀서 선택하게 어떤 을 위해 유형을 소비자가에 대해 아무것도 알 수 없다하고 . 한 가지 예가 있고이 값을 에 제공 하여 값으로 바꿀 수 있다는 점을 제외하고 . 다시 말해, type 값은 어떻게 든 생산 방법을 알고 있습니다. 중간 유형을 제거하고 다음 과 같이 말할 수 있습니다.Xa:Xf:X->intTXXaintfTintX

T = int

보편적으로 정량화 된 것은 약간 다릅니다.

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

이 수단 : 유형의 값은 T모든 유형을 할 수는 없으며 X, 그것은 값을 생성합니다 a:X, 그리고 함수 f:X->int 에는 어떤 문제 X입니다 . 즉, type 값을 가진 소비자는에 T대한 모든 유형을 선택할 수 있습니다 X. 그리고 유형의 값을 생산하는 사람 T은 전혀 알 수 없지만 X을 (를) a선택 하여 값을 생성 X할 수 있어야하며 이러한 값을으로 바꿀 수 있어야합니다 int.

상상할 수있는 모든 유형의 값을 생성 할 수있는 프로그램이 없으므로이 유형을 구현하는 것은 불가능합니다. 부조리와 같은 부조리를 허용하지 않는 한 null.

실재는 쌍이기 때문에 실재 인수는 currying을 통해 범용 인수로 변환 될 수 있습니다 .

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

와 같다:

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

전자는 2 계급 실재입니다. 이것은 다음과 같은 유용한 속성으로 이어집니다.

실재적으로 정량화 된 모든 유형의 순위 n+1는 보편적으로 정량화 된 유형의 순위 n입니다.

실존을 Skolemization 이라고하는 범용으로 바꾸는 표준 알고리즘이 있습니다 .


7
Skolemization을 언급하는 것이 유용 할 수도 있고 그렇지 않을 수도 있습니다. en.wikipedia.org/wiki/Skolem_normal_form
Geoff Reedy

34

두 개념이 상호 보완 적이므로 하나는 다른 유형의 "반대"이기 때문에 실재 유형과 보편적 유형을 함께 설명하는 것이 합리적이라고 생각합니다.

필자는 그 지식이 충분하지 않기 때문에 실재적 유형 (정확한 정의 제공, 가능한 모든 용도 나열, 추상 데이터 유형과의 관계 등)에 대한 모든 세부 사항에 대답 할 수는 없습니다. 이 HaskellWiki 기사 가 실존 유형의 주된 효과로 기술 한 내용 만 (Java를 사용하여) 설명하겠습니다 .

기존 유형은 여러 가지 다른 목적으로 사용될 수 있습니다 . 그러나 그들이하는 일은 오른쪽에 유형 변수를 '숨기는 것'입니다. 일반적으로 오른쪽에 나타나는 모든 유형 변수는 왼쪽에도 나타납니다. […]

설정 예 :

다음 의사 코드는 Java를 수정하기가 쉽지만 유효한 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일부 유형의 α를 저장 하고 동일한 유형의 선택적 leftright하위 트리에 대한 참조를 갖습니다 .

  • 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을 확장합니다).
Craig P. Motlin

1
나는 내 대답이 실존하는 것이 무엇인지 실제로 설명 하지 못한다고 믿었고, 나는 "진실"에 더 가깝다고 생각하는 Kannan Goudan의 대답의 첫 두 단락과 비슷한 또 다른 것을 쓰는 것을 고려하고 있습니다. @Craig : 제네릭과 비교하는 Object것은 매우 흥미 롭습니다. 둘 다 정적 타입 독립적 코드를 작성할 수 있다는 점에서 비슷하지만 전자 (제네릭)는 거의 모든 가용 타입 정보를 버리지 않습니다. 이 목표를 달성하십시오. 이러한 의미에서 제네릭은 ObjectIMO 의 해결책 입니다.
stakx-더 이상

1
@stakx, (유효 자바에서)이 코드에서 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)여전히 함수 내에서 알려져 있지 않고, 여전히 발신자에 의해 결정 이 전달되는 트리 선택할 수있어 발신자이기 때문입니다. 사람들이 자바의 존재 형태를 호출하더라도, 그것은하지 않습니다. ?자리 수있는 몇 가지 상황에서 자바 existentials의 양식을 구현하는 데 사용할 수 있지만, 그들 중 하나가 아닙니다.
피터 홀

15

이것들은 모두 좋은 예이지만, 조금 다르게 대답하기로 선택합니다. 수학에서 ∀x를 상기하십시오. P (x)는 "모든 x에 대해 P (x)를 증명할 수 있습니다"를 의미합니다. 다시 말해, 그것은 일종의 함수입니다. 당신은 나에게 x를 주었고 나는 당신을 위해 그것을 증명할 방법이 있습니다.

유형 이론에서 우리는 증거에 대한 것이 아니라 유형에 대해 이야기하고 있습니다. 그래서이 공간에서 우리는 "당신이 나에게 준 X 타입에 대해, 나는 당신에게 특정 타입 P를 줄 것입니다"를 의미합니다. 이제 X는 X라는 유형 외에 X에 대한 많은 정보를 제공하지 않기 때문에 P는 많은 것을 할 수 없지만 몇 가지 예가 있습니다. P는 "동일한 유형의 모든 쌍"유형을 작성할 수 있습니다 P<X> = Pair<X, X> = (X, X). 또는 옵션 유형을 만들 수 있습니다. P<X> = Option<X> = X | Nil여기서 Nil은 null 포인터의 유형입니다. 목록을 만들 수 있습니다 : List<X> = (X, List<X>) | Nil. 마지막 요소는 재귀 적이며, 값은 List<X>첫 번째 요소가 X이고 두 번째 요소가 a 인 경우 쌍입니다. List<X>그렇지 않으면 널 포인터입니다.

이제 수학 ∃x에서. P (x)는 "P (x)가 참인 특정 x가 있음을 증명할 수 있습니다"를 의미합니다. 많은 x가있을 수 있지만 그것을 증명하기에는 충분합니다. 그것을 생각하는 또 다른 방법은 비어 있지 않은 증거와 증거 쌍 {(x, P (x))}이 있어야한다는 것입니다.

유형 이론으로 번역 : 패밀리 ∃X.P<X>의 유형은 X 유형과 해당 유형 P<X>입니다. 우리가 X에게 P를주기 전에 (X를 제외하고는 X에 관한 모든 것을 거의 알지 못했음) 지금은 그 반대가 사실입니다. P<X>X에 대한 정보를 제공하겠다고 약속하지는 않습니다. X가 있고 실제로 유형이라는 것입니다.

이것이 어떻게 유용합니까? P는 내부 유형 X를 노출시키는 방법이 될 수 있습니다. 예를 들어 상태 X의 내부 표현을 숨기는 객체가 있습니다. 직접 조작 할 방법은 없지만 그 효과를 관찰 할 수는 있습니다. 이 유형에는 여러 가지 구현이있을 수 있지만 어떤 유형을 선택했는지에 관계없이 이러한 유형을 모두 사용할 수 있습니다.


2
흠 그러나 함수 P<X>P(동일한 기능 및 컨테이너 유형이라고 말하지만 함수가 포함되어 X있음을 알지 못함) 알면 무엇을 얻을 수 있습니까?
Claudiu

3
엄밀히 말하면 의 진실성 ∀x. P(x)에 대한 가능성에 대해서는 아무 의미가 없습니다 P(x).
R .. GitHub 중지 지원 얼음

11

질문에 직접 대답하려면 :

범용 유형의 T경우 type 매개 변수 를 사용해야합니다 X. 예를 들어 T<String>또는 T<Integer>. 존재 T하는 유형의 경우 알 수 없거나 관련이 없으므로 해당 유형 매개 변수를 포함하지 마십시오 T(또는 Java에서 T<?>).

추가 정보 :

범용 / 추상 유형과 실존 유형은 객체 / 함수의 소비자 / 클라이언트와 객체 / 함수의 생산자 / 구현 사이의 이중성의 관점입니다. 한쪽이 범용 유형을 볼 때 다른 쪽은 실존 유형을 볼 수 있습니다.

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();
  • a의 관점에서 고객MyClass, T당신이 모든 유형을 대체 할 수 있기 때문에 보편적 T해당 클래스를 사용할 때 당신은의 인스턴스를 사용할 때마다 당신은 T의 실제 유형을 알고 있어야합니다MyClass
  • 인스턴스 메소드 MyClass자체 의 관점 T에서 실제 유형을 알지 못하기 때문에 실존 적입니다.T
  • Java에서는 ?실존 유형을 나타냅니다. 따라서 클래스 내부에있을 때는 T기본적으로 ?입니다. 당신의 인스턴스를 처리하는 경우 MyClassT실존을, 당신은 선언 할 수 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에서는 모든 비 최종 비 기본 유형이 부분적으로 존재합니다. 이상하게 들릴 수도 있지만, 대신 선언 된 변수 ObjectObject대신 서브 클래스 일 수 있으므로 "이 유형 또는 서브 클래스"만 특정 유형을 선언 할 수 없습니다. 따라서 객체는 비트 상태와 해당 상태에서 작동하는 함수 목록으로 표시됩니다. 호출 할 함수는 런타임에 조회에 의해 결정됩니다. 이것은 존재 상태 부분과 해당 상태에서 작동하는 함수가있는 위의 존재 유형을 사용하는 것과 매우 유사합니다.

서브 타이핑 및 캐스트가없는 정적으로 유형이 지정된 프로그래밍 언어에서 실존 유형을 사용하면 다른 유형의 객체 목록을 관리 할 수 ​​있습니다. 의 목록은 T<Int>을 포함 할 수 없습니다 T<Long>. 그러나의 목록 T<?>에는의 변형이 포함될 수 있으므로 T많은 다른 유형의 데이터를 목록에 넣고 필요에 따라 모두 int로 변환하거나 데이터 구조 내에서 제공되는 모든 작업을 수행 할 수 있습니다.

클로저를 사용하지 않고 항상 존재 유형이있는 레코드를 레코드로 변환 할 수 있습니다. 클로저는 또한 존재하는 변수로, 클로저가 닫힌 자유 변수는 호출자에게 숨겨져 있습니다. 따라서 클로저를 지원하지만 실존 유형은 지원하지 않는 언어를 사용하면 객체의 실존 부분에 넣은 것과 동일한 숨겨진 상태를 공유하는 클로저를 만들 수 있습니다.


11

실재 유형은 불투명 유형입니다.

유닉스에서 파일 핸들을 생각하십시오. 당신은 그 타입이 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);

변수 exfile은 int가 아니고 char*struct 파일 이 아닌 int가 아닙니다 . 타입 시스템에서 표현할 수있는 것은 없습니다. 유형을 알 수없는 변수를 선언 할 수 없으며 알 수없는 유형으로 포인터를 캐스트 할 수 없습니다. 언어는 당신을 허용하지 않습니다.


9
작동하지 않습니다. 의 서명이있는 경우 read입니다 ∃T.read(T file, ...)후 아무것도 첫 번째 매개 변수로 전달할 수 있습니다. 작동은 fopen파일 핸들 동일한 존재에 의해 범위가 지정된 읽기 함수를 반환하는 것입니다 .∃T.(T, read(T file, ...))
Kannan Goundan

2
이것은 단지 ADT에 대해서만 말하는 것 같습니다.
kizzx2

7

내가 조금 늦게 온 것 같지만 어쨌든이 문서는 실존 유형이 무엇인지에 대한 또 다른 견해를 추가하지만, 언어에 구애받지 않지만 실존 유형을 이해하는 것이 훨씬 쉬워야 합니다. http : //www.cs.uu .nl / groups / ST / Projects / ehc / ehc-book.pdf (8 장)

보편적으로 정량화 된 유형과 실재적으로 정량화 된 유형의 차이점은 다음과 같은 관찰로 특징 지을 수 있습니다.

  • ∀ 정량화 된 유형의 값을 사용하면 정량화 된 유형 변수의 인스턴스화를 위해 선택할 유형이 결정됩니다. 예를 들어, ID 함수 "id :: ∀aa → a"의 호출자는이 특정 id의 응용에 대해 유형 변수 a에 대해 선택할 유형을 결정합니다. 함수 어플리케이션 "id 3"의 경우이 유형은 Int와 같습니다.

  • ∃ 정량화 된 유형으로 값을 생성하면 정량화 된 유형 변수의 유형이 결정되고 숨겨집니다. 예를 들어, "∃a. (a, a → Int)"의 작성자는 "(3, λx → x)"에서 해당 유형의 값을 구성했을 수 있습니다. 다른 제작자는“( 'x', λx → ord x)”와 동일한 유형의 값을 구성했습니다. 사용자 관점에서 두 값은 동일한 유형을 가지므로 상호 교환이 가능합니다. 값은 유형 변수 a에 대해 선택된 특정 유형을 가지고 있지만 어떤 유형을 알지 못하므로이 정보를 더 이상 이용할 수 없습니다. 이 값 특정 유형 정보는 '잊혀졌습니다'. 우리는 그것이 존재한다는 것을 알고 있습니다.


1
이 링크가 질문에 대한 답변을 제공 할 수 있지만 여기에 답변의 필수 부분을 포함시키고 참조 용 링크를 제공하는 것이 좋습니다. 링크 된 페이지가 변경되면 링크 전용 답변이 유효하지 않을 수 있습니다.
sheilak

1
@sheilak : 제안에 감사 대답을 업데이트
themarketka

5

유형 매개 변수의 모든 값에 대해 범용 유형이 존재합니다. 존재 유형은 존재 유형의 제한 조건을 만족하는 유형 매개 변수의 값에 대해서만 존재합니다.

예를 들어 스칼라에서 실존 유형을 표현하는 한 가지 방법은 일부 상한 또는 하한으로 제한되는 추상 유형입니다.

trait Existential {
  type Parameter <: Interface
}

마찬가지로 제한된 범용 유형은 다음 예와 같이 실존 적 유형입니다.

trait Existential[Parameter <: Interface]

Interface인스턴스화 할 수 있는 하위 유형은를 구현 Existential해야하는 하위 유형을 정의해야 하므로 모든 사용 사이트에서 사용할 수 있습니다 .type ParameterInterface

스칼라에서 실존 적 유형 의 퇴화 사례 는 결코 참조되지 않으므로 어떤 하위 유형으로도 정의 될 필요가없는 추상 유형입니다. 이것은 List[_] 스칼라List<?>자바 의 약식 표기법을 효과적으로 가지고 있습니다.

제 답변은 추상적이고 실존적인 유형 을 통합하려는 Martin Odersky의 제안 에서 영감을 받았습니다 . 동반 슬라이드 이해 도움이됩니다.


1
위의 자료 중 일부를 읽었을 때 내 이해를 잘 요약 한 것처럼 보입니다. 유니버설 유형 ∀x.f(x)은 수신 기능에 불투명하고 기존 유형 ∃x.f(x)은 특정 속성을 갖는 것으로 제한됩니다. 일반적으로 모든 매개 변수는 해당 기능이 직접 조작하기 때문에 모든 매개 변수입니다. 그러나 일반 매개 변수는 함수가 다음과 같은 참조를 얻는 것과 같은 기본 범용 조작을 넘어서 관리하지 않으므로 범용 유형을 가질 수 있습니다.∀x.∃array.copy(src:array[x] dst:array[x]){...}
George

여기에 설명 된 것처럼 stackoverflow.com/a/19413755/3195266 유형 멤버는 ID 유형을 통해 범용 정량을 에뮬레이션 할 수 있습니다. 그리고 forSome유형 매개 변수 존재 수량이 있습니다.
Netsu 2018 년

3

추상 데이터 유형과 정보 숨기기에 대한 연구는 실존 유형을 프로그래밍 언어로 가져 왔습니다. 데이터 유형을 추상화하면 해당 유형에 대한 정보가 숨겨 지므로 해당 유형의 클라이언트는이를 남용 할 수 없습니다. 객체에 대한 참조가 있다고 가정 해보십시오 ... 일부 언어에서는 해당 참조를 바이트에 대한 참조로 캐스팅하고 해당 메모리 조각에 대해 원하는 것을 수행 할 수 있습니다. 프로그램의 동작을 보장하기 위해 언어 디자이너가 개체의 디자이너가 제공하는 방법을 통해서만 개체에 대한 참조에 대해서만 행동하도록하는 것이 유용합니다. 유형이 존재한다는 것을 알고 있지만 더 이상은 없습니다.

보다:

추상 유형에는 기존 유형, MITCHEL 및 PLOTKIN이 있습니다.

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);
}

"기존"은 여기에 정의 된 규칙을 따르는 유형이 있음을 의미합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.