Varoluşçu tip nedir?


173

Ben Wikipedia makalesi okumak Varoluşçu türleri . Varoluşçu operatör (∃) yüzünden bunlara varoluşçu tipler denildiğini anladım. Yine de bunun ne anlama geldiğinden emin değilim. Arasındaki fark nedir

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

ve

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

?


8
Bu programmers.stackexchange.com için iyi bir konu olabilir. programmers.stackexchange.com
jpierson

Yanıtlar:


194

Birisi ∀Xsöylediği evrensel bir türü tanımladığında : İstediğiniz türü takabilirsiniz, işimi yapmak için tür hakkında hiçbir şey bilmeme gerek yok, sadece opak olarak anlatacağımX .

Birisi varoluşsal bir tür tanımladığında ∃Xşöyle der: Burada istediğim türü kullanacağım; tür hakkında hiçbir şey bilmeyeceksiniz, bu yüzden sadece opak olarak başvurabilirsinizX .

Evrensel türler aşağıdakileri yazmanıza izin verir:

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

copyFonksiyon haberi yok Taslında olacak, ama bu gerekmez.

Varoluşçu türler aşağıdaki gibi şeyler yazmanıza izin verir:

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

Listedeki her sanal makine uygulaması farklı bir bayt kodu türüne sahip olabilir. runAllCompilersİşlevin, derlenmiş türüdür haberi yok, ama gerekmez; Bütün bu baytkod röle olduğunu mu VirtualMachine.compilehiçVirtualMachine.run .

Java tipi joker karakterler (ör:) List<?>çok sınırlı varoluşsal türlerdir.

Güncelleme: Varolan türleri evrensel türlerle simüle edebileceğinizi belirtmeyi unutmayın. İlk olarak, type parametresini gizlemek için evrensel türünüzü sarın. İkincisi, kontrolü tersine çevirin (bu, varoluşlar ve evrenseller arasındaki birincil fark olan yukarıdaki tanımlarda "siz" ve "I" bölümünü etkili bir şekilde değiştirir).

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

Şimdi evrensel olarak yazılmış bir fonksiyona sahip olan VMWrapperkendi çağrımıza sahip olabiliriz . Net etki aynıdır, kodumuz opak olarak ele alınmalıdır.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 uygulaması örneği:

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 çok yararlı, ama biraz kavraması zor bir cevap için: 1. Varoluşsal ve evrensel türlerin ikili doğası hakkında daha açık olsaydınız yardımcı olacağını düşünüyorum. Sadece kazayla ilk iki paragrafı çok benzer şekilde nasıl ifade ettiğinizi anladım; ancak daha sonra her iki tanımın da temelde aynı olduğunu, ancak "I" ve "siz" terimlerinin tersine çevrildiğini açıkça belirtirsiniz. Ayrıca, "Ben" ve "siz" in neyi ifade etmesi gerektiğini hemen anlamadım.
stakx - artık

2
(devamı :) 2.List<∃B:VirtualMachine<B>> vms veya içindeki matematiksel gösterimin anlamını tam olarak anlamıyorum for (∃B:VirtualMachine<B> vm : vms). (Bu türler genel tür olduğundan, ?"kendi kendine yapılan" sözdizimi yerine Java'nın joker karakterlerini kullanamaz mıydınız?) Ben böyle bir genel türler ∃B:VirtualMachine<B>dahil, ancak bunun yerine "düz" bir kod örneği var yardımcı olabilir düşünüyorum ∃B, çünkü genel türler ilk kod örneklerinizden sonra evrensel türlerle kolayca ilişkilendirilebilir.
stakx - artık

2
Ben ∃Bkantifikasyonun nerede gerçekleştiği konusunda açık görüşlüydüm. Joker karakter sözdizimi ile niceleyici ima edilir ( List<List<?>>aslında anlamına gelir ∃T:List<List<T>>ve değildir List<∃T:List<T>>). Ayrıca, açık kantifikasyon, tipe atıfta bulunmanıza izin verir (tipin bayt kodunu Bgeçici bir değişkende saklayarak bundan yararlanmak için örneği değiştirdim ).
Kannan Goundan

2
Burada kullanılan matematiksel gösterim cehennem kadar özensizdir, ancak bunun cevabın hatası olduğunu düşünmüyorum (standarttır). Yine de, belki de varoluşsal ve evrensel nicelik belirleyicileri bu şekilde kötüye kullanmamak ...
Noldorin

2
@Kannan_Goundan, Java joker karakterlerinin bunun çok sınırlı bir sürümü olduğunu söyleyenlere bilmek istiyorum. İlk runAllCompilers örnek işlevinizi saf Java'da (wilcard parametresini almak (ad vermek) için bir yardımcı işlevle) uygulayabileceğinizi biliyor musunuz?
LP_

107

Değeri hayati bir tip beğendiniz ∃x. F(x) bir çift kısmını içeren tip x bir değer Çeşidi F(x). Gibi bir polimorfik tür bir değer ise ∀x. F(x)a, fonksiyon bir tür alır xve üreten tipte bir değer F(x). Her iki durumda da, tür bazı yapıcıların üzerine kapanır F.

Bu görünümün türleri ve değerleri karıştırdığını unutmayın. Varoluşsal kanıt bir tür ve bir değerdir. Evrensel kanıt, türe (veya türlerden değerlere eşleme) göre dizine eklenmiş bir değerler ailesidir.

Dolayısıyla, belirttiğiniz iki tür arasındaki fark aşağıdaki gibidir:

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

Bu şu anlama gelir: Bir tür değeri , Tadlı bir tür X, bir değer a:Xve bir işlev içerir f:X->int. Bir tür değer üreticisi herhangi bir türü Tseçer ve bir tüketici hakkında hiçbir şey bilmez . Bunun dışında bir örnek olması ve bu değerin verilmek suretiyle bir değere dönüştürülmesi dışında . Başka bir deyişle, tür değeri bir şekilde nasıl üretileceğini bilir . Ara türü ortadan kaldırabilir ve sadece şunu söyleyebiliriz:XXaintfTintX

T = int

Evrensel olarak ölçülen, biraz farklıdır.

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

Bu araçlar: tipte bir değer Ther tür verilebilir Xve bir değer üretecek a:Xve fonksiyon f:X->int hiçbir yaptığım önemli Xolduğunu . Başka bir deyişle: türdeki tüketiciler Tiçin herhangi bir türü seçebilir X. Ve türdeki bir üretici, Thiçbir şey bilmiyor X, ancak aherhangi bir seçim için bir değer üretebilmeli Xve böyle bir değeri bir haline dönüşebilmelidir int.

Açıkçası bu türün uygulanması imkansızdır, çünkü akla gelebilecek her türden bir değer üretebilecek bir program yoktur. Tabii saçmalıklara nullveya diplere izin vermedikçe .

Bir varoluş bir çift olduğundan, varoluşçu bir argüman, köri yoluyla evrensel bir argümana dönüştürülebilir .

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

aynıdır:

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

Birincisi sıra-2 varoluşudur. Bu, aşağıdaki yararlı özelliğe yol açar:

Varoluşsal olarak nicelendirilen her rütbe türü, n+1evrensel olarak nicelendirilmiş bir rütbe türüdür n.

Varoluşları Skolemizasyon adı verilen evrensellere dönüştürmek için standart bir algoritma vardır .



34

Varolan türleri evrensel tiplerle birlikte açıklamanın mantıklı olduğunu düşünüyorum, çünkü iki kavram birbirini tamamlayıcı niteliktedir, yani biri diğerinin "zıttı" dır.

Varoluşçu türlerle ilgili her ayrıntıya cevap veremiyorum (tam bir tanım vermek, tüm olası kullanımları listelemek, soyut veri türleriyle ilişkilerini vb.) Çünkü bunun için yeterince bilgili değilim. Ben sadece (Java kullanarak) bu HaskellWiki makalenin varoluşçu türlerin temel etkisi olarak belirttiklerini göstereceğim:

Varoluşçu tipleri edilebilir kullanılan birkaç farklı amaçlar için. Ancak yaptıkları şey sağdaki tip değişkenini 'gizlemek'. Normalde, sağda görünen herhangi bir tür değişkeni de solda görünmelidir […]

Örnek kurulum:

Aşağıdaki sözde kod, düzeltmek için yeterince kolay olsa da, oldukça geçerli bir Java değildir. Aslında, bu cevapta yapacağım şey tam olarak bu!

class Tree<α>
{
    α       value;
    Tree<α> left;
    Tree<α> right;
}

int height(Tree<α> t)
{
    return (t != null)  ?  1 + max( height(t.left), height(t.right) )
                        :  0;
}

Bunu kısaca açıklayayım. Tanımlıyoruz…

  • Tree<α>ikili ağaçtaki bir düğümü temsil eden özyinelemeli tip . Her düğüm avalue tipinde bir a depolar ve isteğe bağlı referanslara sahiptirleftright ve aynı tipte ve alt ağaçlara içerir.

  • heightherhangi bir yaprak düğümünden kök düğüme en uzak mesafeyi döndüren bir işlevt .

Şimdi yukarıdaki sahte kodu height uygun Java sözdizimine çevirelim! (Kısaca nesne yönelimi ve erişilebilirlik değiştiricileri gibi kısacası çıkarmaya devam edeceğim.) İki olası çözüm göstereceğim.

1. Evrensel tip çözüm:

En belirgin düzeltme, imza heightparametresi α'yı imzasına sokarak genel bir yöntem oluşturmaktır :

<α> int height(Tree<α> t)
{
    return (t != null)  ?  1 + max( height(t.left), height(t.right) )
                        :  0;
}

Bu, isterseniz değişkenleri bildirmenize ve bu işlevin içinde α türünde ifadeler oluşturmanıza olanak tanır . Fakat...

2. Varoluşçu tip çözüm:

Metodumuzun vücuduna bakarsanız, α ! Bu türden hiçbir ifade veya bu türle bildirilen herhangi bir değişken yok ... Öyleyse, neden heightjenerik yapmamız gerekiyor ? Neden α'yı unutamıyoruz ? Sonuç olarak şunları yapabiliriz:

int height(Tree<?> t)
{
    return (t != null)  ?  1 + max( height(t.left), height(t.right) )
                        :  0;
}

Bu cevabın en başında yazdığım gibi, varoluşsal ve evrensel tipler tamamlayıcı / ikili niteliktedir. Bu nedenle, evrensel tip çözüm height daha genel hale getirilecekse , varoluşçu tiplerin zıt etkiye sahip olmasını beklemeliyiz: daha az genel hale getirmek , yani type parametresini gizlemek / kaldırmak α .

Sonuç olarak, artık t.valuebu yöntemin türüne başvuramaz veya bu türden herhangi bir ifadeyi değiştiremezsiniz, çünkü herhangi bir tanımlayıcı bağlı değildir. ( ?Joker karakter , bir türü "yakalayan" bir tanımlayıcı değil, özel bir işarettir.) t.valueEtkin bir şekilde opak hale gelmiştir; belki de onunla yapabileceğiniz tek şey onu yazmaktır Object.

Özet:

===========================================================
                     |    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
İyi açıklama. T.value değerini Object olarak kullanmanıza gerek yoktur, sadece Object olarak başvurabilirsiniz. Varoluşçu tipin yöntemi bu nedenle daha genel hale getirdiğini söyleyebilirim. T.value hakkında bildiğiniz tek şey, bunun bir Nesne olmasıdır, ancak α hakkında belirli bir şey söyleyebilirsiniz (α, Serializable'ı genişletir gibi).
Craig P. Motlin

1
Bu arada cevabımın varoluşların gerçekte ne olduğunu açıklamadığına inanmaya başladım ve Kannan Goudan'ın cevabının ilk iki paragrafına benzeyen başka bir yazı yazmayı düşünüyorum, ki bu da “gerçeğe” daha yakın. Bununla birlikte, @Craig: Jeneriklerle karşılaştırmak Objectoldukça ilginç: Her ikisi de statik olarak tipten bağımsız kod yazmanıza izin verdikleri için benzer olsa da, eski (jenerikler) mevcut tür bilgilerinin neredeyse tamamını bu hedefe ulaşmak. Bu anlamda jenerik ilaçlar ObjectIMO için bir çare .
stakx - artık

1
@stakx, (Etkin Java) bu kod 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))); } , Ea, universal typeve ?bir temsil eder existential type?
Kevin Meredith

Bu cevap doğru değil. ?Tip int height(Tree<?> t)hala işlev içinde bilinmemektedir ve hala bir arayan tarafından belirlenir içeri geçmesine hangi ağaç seçmek lazım arayan çünkü. Kişiler bu Java varoluşsal tip çağrı bile, öyle değil. Yer ?tutucu , bazı durumlarda Java'da bir tür varoluş uygulamak için kullanılabilir, ancak bu bunlardan biri değildir.
Peter Hall

15

Bunların hepsi güzel örnekler, ama ben biraz farklı cevap vermeyi tercih ediyorum. Matematikten hatırlayın, o ∀x. P (x) "tüm x'ler için bu P (x) 'i kanıtlayabilirim" anlamına gelir. Başka bir deyişle, bu bir tür işlev, bana bir x veriyorsunuz ve bunu sizin için kanıtlayacak bir yöntemim var.

Tür teorisinde, kanıtlardan değil, türlerden bahsediyoruz. Yani bu alanda "bana verdiğin herhangi bir X türü için sana özel bir P türü vereceğim" deriz. Şimdi, X hakkında bir tür olmasının yanı sıra P hakkında çok fazla bilgi vermediğimizden, P bununla pek bir şey yapamaz, ancak bazı örnekler vardır. P "Aynı türdeki tüm çiftleri" türünü oluşturabilir: P<X> = Pair<X, X> = (X, X). Veya şu seçenek türünü oluşturabiliriz: P<X> = Option<X> = X | Nilburada Nil null işaretçilerin türüdür. Biz bunun dışında bir listesini yapabilirsiniz: List<X> = (X, List<X>) | Nil. Sonuncunun özyinelemeli olduğuna dikkat edin; değerlerinin List<X>, ilk öğenin X ve ikinci öğenin bir çift olduğu List<X>ya da boş bir işaretçi olduğu çiftlerdir .

Şimdi, matematik inx. P (x), "P (x) doğru olacak şekilde belirli bir x olduğunu kanıtlayabilirim" anlamına gelir. Böyle birçok x olabilir, ancak kanıtlamak için bir kişi yeterlidir. Bunu düşünmenin başka bir yolu da boş olmayan bir dizi kanıt ve kanıt çifti bulunması gerektiğidir {(x, P (x))}.

Tip teorisine çevrilir: Ailede ∃X.P<X>bir tip X tipi ve karşılık gelen tiptir P<X>. X'i P'ye vermeden önce (X ile P hakkındaki her şeyi çok az biliyorduk) şimdi tersinin doğru olduğuna dikkat edin. P<X>X hakkında herhangi bir bilgi vermeyi vaat etmiyor, sadece bir tane olduğunu ve gerçekten bir tür olduğunu vaat ediyor.

Bu nasıl faydalı? P, iç tipi X'i ortaya çıkarmanın bir yolu olan bir tür olabilir. Bir örnek, X durumunun iç temsilini gizleyen bir nesne olabilir. Bu tür birçok uygulama olabilir, ancak hangi türün seçildiğine bakılmaksızın tüm bu türleri kullanabilirsiniz.


2
Hmm ama P<X>bunun yerine bir işlev olduğunu bilerek işlev ne kazanıyor P(aynı işlevsellik ve kap türü, diyelim ama içerdiğini bilmiyorsunuz X)?
Claudiu

3
Kesin olarak konuşmak gerekirse, sadece gerçeğin doğruluğu ile ∀x. P(x)ilgili bir şey ifade etmez P(x).
R .. GitHub BUZA YARDIMCI DURDUR

11

Sorunuzu doğrudan cevaplamak için:

Evrensel tipte kullanımları Ttype parametresini içermelidir X. Örneğin T<String>veyaT<Integer> . Varoluşçu tip kullanımları için Tbu tip parametresini dahil etmeyin, çünkü bilinmeyen veya alakasız - sadece kullanın T(veya Java'daT<?> ).

Daha fazla bilgi:

Evrensel / soyut türler ve varoluşsal türler, bir nesnenin / fonksiyonun tüketici / müşterisi ile onun üreticisi / uygulaması arasındaki perspektifin bir dualitesidir. Bir taraf evrensel bir tip gördüğünde diğeri varoluşsal bir tip görür.

Java'da genel bir sınıf tanımlayabilirsiniz:

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();
  • Bir perspektifinden bakıldığında istemci arasında MyClass,T sizin için her türlü yerini alabilir çünkü evrenseldir TEğer o sınıfı kullandığınızda ve bir örneğini her kullandığınızda sizi T asıl türünü bilmeniz gerekirMyClass
  • MyClassKendi başına örnek yöntemler açısından ,T açısından varoluşsaldır çünkü gerçek türdenT
  • Java'da ?varoluşsal türü temsil eder - bu nedenle sınıfın içindeyken Ttemelde olur ?. Eğer bir örneğini işlemek istiyorsanız MyClassile Tvaroluşsal, sen ilan edebilir MyClass<?>gibi secretMessage()Yukarıdaki örnekte.

Varoluşçu türler bazen başka bir yerde tartışıldığı gibi bir şeyin uygulama ayrıntılarını gizlemek için kullanılır. Bunun bir Java sürümü şöyle görünebilir:

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

Bunu düzgün bir şekilde yakalamak biraz zor çünkü Java'nın olmadığı bir tür fonksiyonel programlama dilinde gibi davranıyorum. Ancak buradaki nokta, bir çeşit devletin yanı sıra bu eyalette çalışan işlevlerin bir listesini yakaladığınız ve eyalet bölümünün gerçek türünü bilmediğiniz, ancak işlevler zaten bu türle eşleştirildiklerinden beri yapıyor .

Şimdi, Java'da nihai olmayan ilkel olmayan türler kısmen varoluşsaldır. Bu garip gelebilir, ancak olarak bildirilen bir değişken bunun yerine Objectbir alt sınıf Objectolabileceğinden, belirli bir türü, yalnızca "bu tür veya bir alt sınıfı" bildiremezsiniz. Ve böylece, nesneler biraz durum artı bu durumda çalışan işlevlerin bir listesi olarak temsil edilir - tam olarak hangi işlev çağırılacağı çalışma zamanında arama ile belirlenir. Bu, bir varoluşsal durum parçasına ve bu durumda çalışan bir işleve sahip olduğunuz varoluşçu türlerin kullanımına çok benzer.

Alt tür ve döküm olmadan statik olarak yazılan programlama dillerinde, varoluşçu türler farklı türdeki nesnelerin listelerini yönetmeye izin verir. Listesinde T<Int>a bulunamaz T<Long>. Bununla birlikte, bir liste, birçok farklı veri türünü listeye koymaya ve bunları isteğe bağlı olarak bir int'e (veya veri yapısı içinde sağlanan işlemleri yap) dönüştürmeye izin veren T<?>herhangi bir varyasyonu içerebilir T.

Varoluşçu tipte bir kaydı, kapakları kullanmadan hemen hemen her zaman bir kayda dönüştürebilirsiniz. Bir kapatma da varoluşsal olarak yazılır, çünkü kapatıldığı serbest değişkenler arayandan gizlenir. Böylece, kapanışları destekleyen ancak varoluşçu türleri desteklemeyen bir dil, bir nesnenin varoluşsal kısmına koyacağınız aynı gizli durumu paylaşan kapanışlar yapmanıza izin verebilir.


11

Varoluşçu tip opak bir tiptir.

Unix'te bir dosya tanıtıcısı düşünün. Türünün int olduğunu biliyorsunuz, böylece kolayca taklit edebilirsiniz. Örneğin, tanıtıcı 43'ten okumaya çalışabilirsiniz. Bu durumda, programın bu özel tanıtıcıyla açık bir dosyası olması durumunda, okuyacaksınız. Kodunuzun kötü amaçlı olması gerekmez, sadece özensizdir (örneğin, tanıtıcı başlatılmamış bir değişken olabilir).

Varolan bir tür programınızdan gizlenir. Eğer fopenbir varoluşsal türü döndürdü, onunla tek yapabildiği bu varoluşsal türünü kabul bazı kütüphane fonksiyonları ile kullanmaktır. Örneğin, aşağıdaki sözde kod derlenir:

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

"Read" arayüzü şöyle bildirildi:

T tipi vardır, öyle ki:

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

Exfile değişkeni bir int değil char*, bir struct Dosyası değil - tür sisteminde ifade edebileceğiniz hiçbir şey değildir. Türü bilinmeyen bir değişkeni bildiremezsiniz ve mesela o bilinmeyen türe bir işaretçi atamazsınız. Dil sana izin vermiyor.


9
Bu işe yaramaz. İmzası Eğer readedilir ∃T.read(T file, ...)o zaman hiçbir şey ilk parametre olarak geçirebilirsiniz. Ne işe fopen∃T.(T, read(T file, ...))
yarar

2
Bu sadece ADT'lerden bahsediyor gibi görünüyor.
kizzx2

7

Görünüşe göre biraz geç geliyorum, ama yine de, bu belge varoluşçu türlerin ne olduğuna dair başka bir görünüm ekliyor, ancak özellikle dil-agnostik olmasa da, varoluş türlerini anlamak oldukça kolay olmalı: http: //www.cs.uu .nl / groups / ST / Projeler / ehc / ehc-book.pdf (bölüm 8)

Evrensel ve varoluşsal olarak nicelenmiş tip arasındaki fark, aşağıdaki gözlemle karakterize edilebilir:

  • Nicelikli tipte bir değerin kullanılması, nicelikli tip değişkeninin somutlaştırılması için seçilecek tipi belirler. Örneğin, “id :: ∀aa → a” ​​kimlik fonksiyonunun arayanı, bu özel id uygulaması için a tipi değişkeni için seçilecek türü belirler. “İd 3” fonksiyon uygulaması için bu tip Int'ye eşittir.

  • ∃ nicelleştirilmiş tip ile bir değerin oluşturulması, nicelleştirilmiş tip değişkeninin tipini belirler ve gizler. Örneğin, bir “∃a. (A, a → Int)” yaratıcısı, bu tür bir değeri “(3, λx → x)”; başka bir içerik oluşturucu, “('x', λx → ord x)” ile aynı türde bir değer oluşturdu. Kullanıcılar açısından her iki değer de aynı tiptedir ve bu nedenle birbirinin yerine kullanılabilir. Değer, a tipi değişkeni için seçilen belirli bir türe sahiptir, ancak hangi türü bilmiyoruz, bu nedenle bu bilgilerden artık yararlanamıyoruz. Bu değere özgü tür bilgisi 'unutuldu'; sadece var olduğunu biliyoruz.


1
Bu bağlantı soruyu cevaplayabilse de, cevabın temel kısımlarını buraya eklemek ve bağlantıyı referans olarak sağlamak daha iyidir. Bağlantı verilen sayfa değişirse, yalnızca bağlantı yanıtları geçersiz olabilir.
sheilak

1
@sheilak: Cevabı güncelledi, öneri için teşekkürler
themarketka

5

Type parametrelerinin tüm değerleri için evrensel bir tür vardır. Varoluşsal bir tür, yalnızca varoluşçu türün kısıtlamalarını karşılayan type parametresinin (değerlerinin) değerleri için vardır.

Örneğin Scala'da varoluşsal bir türü ifade etmenin bir yolu, bazı üst veya alt sınırlarla sınırlandırılmış soyut bir türdür.

trait Existential {
  type Parameter <: Interface
}

Eşdeğer şekilde kısıtlanmış bir evrensel tip, aşağıdaki örnekteki gibi varoluşsal bir tiptir.

trait Existential[Parameter <: Interface]

Herhangi bir kullanım sitesi çalışabilir Interfaceçünkü herhangi bir somutlaştırılabilir alt tür Existential, type Parameterhangisinin uygulanması gerektiğini tanımlamalıdır Interface.

Bir dejenere durumda Scala hayati bir Çeşidi ifade hiçbir zaman ve bu şekilde her alt tarafından tanımlanan gerekmez soyut bir türüdür. Bunun etkili bir şekilde List[_] Scala ve List<?>Java'da steno gösterimi vardır .

Cevabım Martin Odersky'nin soyut ve varoluş türlerini birleştirme önerisinden ilham aldı . Beraberindeki slayt anlayış yardımcı olur.


1
Yukarıdaki materyallerin bazılarını okuduktan sonra, anlayışımı güzel bir şekilde özetlediniz: Evrensel Tipler, ∀x.f(x)Varoluşçu Tipler, alıcı işlevlerine opakken, ∃x.f(x)belirli özelliklere sahip olmakla sınırlıdır . Tipik olarak, tüm parametreler Varoluşçudur, çünkü fonksiyonları onları doğrudan manipüle edecektir; ancak, genel parametreler Evrensel olan türlere sahip olabilir, çünkü fonksiyon bunları aşağıdaki gibi bir referans alma gibi temel evrensel işlemlerin ötesinde yönetmeyecektir:∀x.∃array.copy(src:array[x] dst:array[x]){...}
George

Burada açıklandığı gibi stackoverflow.com/a/19413755/3195266 türü üyeler kimlik türü yoluyla evrensel nicelemeyi taklit edebilir. Ve elbette forSometip parametresi varoluşsal nicelendirmesi vardır.
Netsu

3

Soyut veri türleri ve bilgi gizleme üzerine yapılan araştırmalar, varolan türleri programlama dillerine getirdi. Bir veri türü özeti oluşturmak, bu türle ilgili bilgileri gizler, bu nedenle bu türden bir istemci kötüye kullanamaz. Diyelim ki bir nesneye referansınız var ... bazı diller bu referansı bayt referansına yönlendirmenize ve o hafızaya istediğiniz her şeyi yapmanıza izin verir. Bir programın davranışını garanti altına almak amacıyla, bir dil için yalnızca nesnenin tasarımcısı tarafından sağlanan yöntemlerle nesneye yapılan başvuruyu gerçekleştirdiğinizi zorlamak yararlıdır. Türün var olduğunu biliyorsunuz, ama daha fazlası değil.

Görmek:

Soyut Türlerin Varoluşçu Tipleri, MITCHEL & PLOTKIN

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


1

Bu diyagramı oluşturdum. Titiz olup olmadığını bilmiyorum. Ama yardımcı olursa sevindim. resim açıklamasını buraya girin


-6

Anladığım kadarıyla arayüzleri / soyut sınıfı tanımlamanın matematik bir yolu.

T = ∃X {Xa'ya gelince; int f (X); }

C # için genel bir soyut türe çevrilir:

abstract class MyType<T>{
    private T a;

    public abstract int f(T x);
}

"Varoluşçu" sadece burada tanımlanan kurallara uyan bir tür olduğu anlamına gelir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.