Neden (veya neden olmasın) varoluşsal tipler fonksiyonel programlamada kötü bir uygulama olarak kabul edilir?


43

Varoluşsal türlere bağlılığı ortadan kaldırarak sürekli olarak yeniden kodlama kodu kullanmak için kullanabileceğim bazı teknikler nelerdir? Tipik olarak bunlar, türünüzün istenmeyen yapılarını diskalifiye etmek ve verilen tür hakkında en az bir bilgi ile tüketime izin vermek için kullanılır (veya benim anlayışım budur).

Herhangi biri, faydalardan bazılarını koruyan kodlara güvenmeyi kaldırmanın basit ve tutarlı bir yolunu buldunuz mu? Ya da en azından önemli bir kod karmaşasının değişiklikle başa çıkmasını gerektirmeden çıkarılmasını sağlayan bir soyutlamada kayma yolları?

Varoluşsal türlerle ilgili daha fazla bilgiyi burada bulabilirsiniz ("cesaretin varsa ..").


8
@RobertHarvey Bu soru hakkında ilk kez düşünmemi sağlayan blog yazısını buldum: Haskell Antipattern: Varoluşlu Typeclass . Ayrıca, Joey Adams’ın bahsettiği makale, Bölüm 3.1’de varlıkları olan bazı amblemleri tanımlamaktadır. Aksine iddialarınız varsa, lütfen paylaşın.
Petr Pudlák

5
@ PetrPudlák: Antipattern'in genel olarak varoluşsal tipler olmadığını, fakat daha basit ve daha kolay (ve Haskell'de daha iyi desteklenen) bir şeyin aynı işi yapması durumunda belirli bir kullanımının olduğunu unutmayın.
CA McCann

10
Belirli bir blog gönderisinin yazarının neden bir görüş ifade ettiğini bilmek istiyorsanız, muhtemelen sormanız gereken kişi yazardır.
Eric Lippert

6
@Ptolemy Bu bir fikir meselesi. Haskell'i yıllarca kullanmak, güçlü bir tip sistemine sahip olmayan bir fonksiyonel dili kullanmayı hayal edemiyorum.
Petr Pudlák

4
@Ptolemy: Haskell'in mantrası "çalışıyorsa derler", Erlangs mantrası "bırakmasın" dır. Dinamik yazma, bir yapıştırıcı olarak iyidir, ama ben şahsen sadece yapıştırıcı kullanarak bir şeyler yapmazdım.
Den

Yanıtlar:


8

İşlevsel programlamada varolan türler gerçekten kötü uygulama olarak kabul edilmez. Sizi tetikleyen şey, varoluşların en çok kullanılan kullanımlarından birinin , birçok insanın kötü bir uygulama olduğuna inandığı varoluşlu tip sınıf antipattern olduğunu düşünüyorum.

Bu model çoğu zaman aynı tip sınıfı uygulayan heterojen şekilde yazılmış elemanların bir listesinin nasıl bulunacağı sorusuna bir cevap olarak ortaya çıkar. Örneğin, Showörnekleri olan bir değerler listesine sahip olmak isteyebilirsiniz :

{-# LANGUAGE ExistentialTypes #-}

class Shape s where
   area :: s -> Double

newtype Circle = Circle { radius :: Double }
instance Shape Circle where
   area (Circle r) = pi * r^2

newtype Square = Square { side :: Double }
    area (Square s) = s^2

data AnyShape = forall x. Shape x => AnyShape x
instance Shape AnyShape where
    area (AnyShape x) = area x

example :: [AnyShape]
example = [AnyShape (Circle 1.0), AnyShape (Square 1.0)]

Bunun gibi kod ile ilgili sorun şudur:

  1. Üzerinde gerçekleştirebileceğiniz tek faydalı işlem AnyShapealanını almaktır.
  2. AnyShapeŞekil türlerinden birini türüne getirmek için yapıcıyı kullanmanız gerekir AnyShape.

Görünen o ki, bu kod parçası size gerçekten bu kısa olandan bir şey elde etmiyor:

class Shape s where
   area :: s -> Double

newtype Circle = Circle { radius :: Double }
instance Shape Circle where
   area (Circle r) = pi * r^2

newtype Square = Square { side :: Double }
    area (Square s) = s^2

example :: [Double]
example = [area (Circle 1.0), area (Square 1.0)]

Çok yöntemli sınıflar söz konusu olduğunda, aynı efekt genellikle daha basit bir şekilde "yöntemlerin kaydı" kodlaması kullanılarak gerçekleştirilebilir - benzer bir sınıf sınıfı kullanmak yerine Shape, alanlarını " Shapetürlerinin " yöntemleri "olan bir kayıt türü tanımlarsınız. ve çevrelerinizi ve karelerinizi Shapes'ye dönüştürecek işlevleri yazarsınız .


Ancak bu, varoluşsal türlerin sorun olduğu anlamına gelmez! Örneğin, Rust'ta , insanların genellikle bir özellik üzerinde varoluşsal bir tür olarak tanımladığı, özellik nesneleri (Rust'in tür sınıflarının sürümleri) tanımladığı özellik nesneleri adı verilen bir özelliği vardır . Eğer varoluşsal sınıflar Haskell'de bir kamaştırıcı ise, bu, Rust'un kötü bir çözüm seçtiği anlamına mı geliyor? Hayır! Haskell dünyasındaki motivasyon, gerçekten prensip değil, sözdizimi ve kolaylıktır.

Bu koyarak bir daha matematiksel bir yolu olduğunu işaret edilir AnyShapeve yukarıdan tipi Doublevardır izomorfik -orada aralarında "kayıpsız dönüşüm" (bit kayan nokta hassas için tasarruf, iyi) 'dir:

forward :: AnyShape -> Double
forward = area

backward :: Double -> AnyShape
backward x = AnyShape (Square (sqrt x))

Yani, kesinlikle konuşursak, birini seçip diğerini seçerek herhangi bir güç kazanmıyor ya da kaybetmiyorsunuz. Bu, seçimin kullanım kolaylığı veya performans gibi diğer faktörlere dayanması gerektiği anlamına gelir.


Ve varoluşsal türlerin bu heterojen listelerin dışında başka kullanımları olduğunu aklınızda bulundurun, bu yüzden bunların olması iyi bir şey. Örneğin, STharici olarak saf fakat dahili olarak hafıza mutasyon işlemlerini kullanan fonksiyonlar yazmamıza izin veren Haskell'in türü, derleme zamanında güvenliği sağlamak için varoluşsal türlere dayanan bir teknik kullanır.

Genel cevap şu ki, genel bir cevap yok. Varoluşsal türlerin kullanımları yalnızca bağlamda değerlendirilebilir - ve hangi dillerin ve sözdiziminin farklı diller tarafından sağlandığına bağlı olarak cevaplar farklı olabilir.


Bu bir izomorfizm değildir.
Ryan Reich

2

Haskell'e fazla aşina değilim, bu yüzden soruyu genel olarak akademik olmayan bir fonksiyonel C # geliştiricisi olarak cevaplamaya çalışacağım.

Bazı okumalar yaptıktan sonra, ortaya çıkıyor:

  1. Java joker karakterleri varoluşsal türlere benzer:

    Scala'nın varoluş tipleri ile Java'nın joker karakterleri arasındaki fark

  2. Joker karakterler tamamen C # dilinde uygulanmaz: genel varyans desteklenir, ancak arama sitesi varyansı şu şekilde değildir:

    C # Generics: Joker karakterler

  3. Her gün bu özelliğe ihtiyacınız olmayabilir, ancak ne zaman bunu hissedeceksiniz (örneğin, işleri yürütmek için ekstra bir tür vermek zorunda kalacaksınız):

    C # genel kısıtlamalarında joker karakterler

Bu bilgilere dayanarak, varoluşsal türler / joker karakterler doğru bir şekilde uygulandığında kullanışlıdır ve kendi başlarına yanlış bir şey yoktur, ancak muhtemelen diğer dil özellikleri gibi kötüye kullanılabilirler.

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.