Ayrımcı sendikalar neden işlevsel programlama ile ilişkilendiriliyor?


30

OO programlamasının yıllarında, ayrımcı sendikaların ne olduğunu anladım, ancak onları gerçekten çok özlemedim. Son zamanlarda C # 'da bazı fonksiyonel programlama yapıyorum ve şimdi onlara sahip olmayı dilediğimi anlıyorum. Bu beni şaşırtıyor çünkü bunun karşısında, ayrımcı sendikalar kavramı işlevsel / OO ikilemesinden oldukça bağımsız görünüyor.

Ayrımcı sendikaları OO'da olacağından daha faydalı kılan işlevsel programlamanın doğasında var olan bir şey var mı, yoksa kendimi sorunu “daha ​​iyi” bir şekilde analiz etmeye zorlayarak, standartlarımı yükseltip şimdi daha iyi bir talepte bulunmamı sağladı mı? modellemek?


İfade sorunu en.wikipedia.org/wiki/Expression_problem alakalı olabilir
xji

Bu soruya gerçekten doğru bir cevap değil, bu yüzden bir yorum olarak cevap vereceğim, ancak Ceylon programlama dili bir birleşim türüne sahip ve görünüşte diğer OO / karma paradigma dillerine giriyorlar - TypeScript ve Scala aklıma geliyor. Ayrıca Java dili numaraları, ayrımcı sendikaların bir uygulaması olarak da kullanılabilir.
Roland Tepp,

Yanıtlar:


45

Ayrımcı sendikalar, vakalara bağlı olarak farklı davranışlar seçtiğiniz, desen eşleştirme ile birlikte parlar. Ancak bu model temelde antitetiktir saf OO prensiplerine aykırıdır.

Saf OO'da davranıştaki farklılıklar kendileri (nesneler) tarafından tanımlanmalı ve kapsüllenmelidir. Bu nedenle, desen eşleştirmeye eşdeğerlik, nesnenin kendisinde tek bir yöntem çağırmak olacaktır, bu daha sonra farklı davranışları tanımlamak için söz konusu alt türler tarafından aşırı yüklenir. Bir nesnenin tipini dışarıdan incelemek (örüntü eşleme yapan şeydir) antipattern olarak kabul edilir.

Temel fark, işlevsel programlamada veri ve davranışın ayrı olduğu ve veri ve davranışların OO'da kapsüllenmesidir.

Bu tarihsel sebep. C # gibi bir dil, daha fazla işlev özelliği ekleyerek klasik bir OO dilden çoklu paradigma diline doğru gelişiyor.


6
Ayrımcı sendika / toplam türü, bir miras ağacı veya bir arabirim uygulayan birden çok sınıf gibi değildir; birçok çeşit değeri olan tek tiptir. Ayrıca kapsüllemeyi engellemezler; Müşterinin birden fazla değer türünüz olduğunu bilmesi gerekmez. Boş bir düğüm ya da bir değer ve başka bir düğüme referans olabilecek bir bağlı liste düşünün. Toplam türler olmadan, değer ve başvuru için değişkenlere sahip olarak, yine de ayrımcılığa uğramış bir birliği kesmekle sonuçlanır, ancak bir nesneyi boş bir düğüm olarak boş bir referansla muamele etmek ve değer değişkeni gibi davranmak mevcut değildir.
Doval

2
Genel olarak, bir sınıftaki tüm olası değer türlerinin değişkenlerini, artı bu türün ne tür bir değer olduğunu ve bununla uyuşmayan değişkenlerin etrafında dans ettiğini söyleyen bir tür bayrak veya enum'u dahil edersiniz. tür.
Doval

7
@Doval Bir arabirim / soyut temel sınıfına sahip olarak, genel olarak türü temsil eden ve türün her durumu için bir alt sınıfa sahip olarak sınıflara cebirsel veri tipinin bir "standart" kodlaması vardır. Desen eşleşmesini işlemek için, her durum için bir işlev alan bir yönteme sahip olursunuz, bu nedenle en üst düzey arabirimde yer alan bir liste List<A>için yöntemdir B Match<B>(B nil, Func<A,List<A>,B> cons). Örneğin, bu tam olarak Smalltalk'ın booleans için kullandığı modeldir. Bu aynı zamanda Scala'nın nasıl kullandığıdır. Çoklu sınıfların kullanılması, gösterilmesi gerekmeyen bir uygulama detayıdır.
Derek Elkins

3
@Doval: Boş referansları açıkça kontrol etmek de gerçekten aptal OO sayılmaz.
JacquesB

@JacquesB Boş denetim bir uygulama detayıdır. Bağlantılı listenin istemcisi için genellikle bir isEmptysonraki düğüme yapılan referansın boş olup olmadığını kontrol eden bir yöntem vardır.
Doval

35

Fonksiyonel programlamayı öğrenmeden önce Pascal ve Ada'da programlanmış, ayrımcı sendikaları işlevsel programlama ile ilişkilendirmiyorum.

Ayrımcı sendikalar bir şekilde mirasın ikilisidir. Birincisi, sabit bir tür kümesinde (sendikadakiler) işlemleri kolayca eklemenize izin verir ve kalıtım, sabit bir işlem kümesine sahip türleri kolayca eklemenizi sağlar. (Her ikisinin de kolayca eklenmesi , ifade problemi olarak adlandırılır ; bu, statik tip sistemli diller için özellikle zor bir problemdir.)

OO'nun türler üzerindeki vurgusu ve işlevler üzerine fonksiyonel programlamanın ikili vurgusu nedeniyle, işlevsel programlama dilleri sendika tipleri için doğal bir afiniteye sahiptir ve kullanımlarını kolaylaştırmak için sözdizimsel yapılar sunar.


7

OO'da sıkça kullanıldığı gibi emperyal programlama teknikleri genellikle iki formata dayanır:

  1. Başarılı ol veya istisna at,
  2. null"Değersiz" olduğunu veya başarısız olduğunu göstermek için geri dönün .

İşlevsel paradigma tipik olarak her ikisinden de kaçınır, başarı / başarısızlık sebebi veya değer / değer içermeyen bir bileşik türü döndürmeyi tercih eder.

Ayrımcı sendikalar bu bileşik türler için faturaya uyuyor. Örneğin, ilk örnekte, geri döndürebilirsiniz trueveya arızayı tanımlayan bazı veri yapıları olabilir. İkinci durumda, bir değeri içeren ya da bir birlik içinde none, nilvb ikinci durumda birçok fonksiyonel diller yerleşik bu değer / hiçbiri birliği temsil edecek bir "belki" veya "seçeneği" türüne sahip olduğunu, bu nedenle sık görülür.

Örneğin, C # ile işlevsel bir stile geçerken, bu bileşik türlerine hızlı bir şekilde gereksinim duyacaksınız. void/throwve nullsadece böyle bir kod ile doğru hissetmiyorum. Ayrımcı sendikalar (DU) tasarıya iyi uyuyor. Böylece kendin de onları istediğin gibi buldunuz, tıpkı çoğumuz gibi.

İyi haber şu ki, örneğin C # modelindeki DU'ları modelleyen pek çok kütüphane var (örneğin kendi Succinc <T> kütüphaneme bakın).


2

Toplam türler, genel OO dillerinde, OO alt tiplemesine benzer bir problemi çözdükleri için genellikle daha az faydalı olacaktır. Onlara bakmanın bir yolu, her ikisinin de alt tiplemeyi ele almasıdır, ancak OO, openbir tanesi bir ebeveyn tipine isteğe bağlı alt tipler ekleyebilir ve toplam tipler, closedyani bir alt tipin hangi alt tiplerin geçerli olduğuna karar vermesidir.

Şimdi, birçok OO dili alt tiplemeyi, kalıtsal yapılar, polimorfizm, referans yazma vb. Gibi diğer kavramlarla birleştirerek bunları daha kullanışlı hale getiriyor. Bunun bir sonucu, (sınıflar ve kurucularla ve ne olursa olsun) kurmak için daha fazla çalışma eğiliminde olmalarıdır, bu yüzden Results ve Options gibi şeyler için kullanılmaya meyilli değillerdi, genel yazım yaygınlaşana kadar.

Ayrıca, çoğu insanın OO programlamaya başladıklarında öğrendikleri gerçek-dünya ilişkilerine odaklanmanın, örneğin Dog isa Animal, yani Integer'ın Sonuç ya da Hata ve sonuç olarak biraz yabancı göründüğünü söyleyebilirim. Fikirler oldukça benzer olsa da.

İşlevsel dillerin neden açık yazı yazmak için kapalı yazmayı tercih edebileceğine gelince, olası bir neden, kalıp eşleştirmeyi tercih etme eğiliminde olmalarıdır. Bu, işlev polimorfizmi için kullanışlıdır, ancak derleyici tüm alt tiplerin örtülüp örtülmediğini statik olarak kontrol edebildiği için kapalı tiplerle de iyi çalışır. Bu, dili daha tutarlı hissettirebilir, ancak herhangi bir içsel fayda olduğuna inanmıyorum (yanılıyor olabilirim).


BTW: Scala mirasını kapattı. sealed"sadece aynı derleme ünitesinde uzatılabilir" anlamına gelir, bu da tasarım zamanındaki alt sınıfları kapatmanızı sağlar.
Jörg W Mittag

-3

Swift mutlu bir şekilde ayrımcı sendikalar kullanıyor, ancak onlara "enums" diyor. Enums, Swift'de sınıf, yapı, enum, tuple ve kapatma olan beş temel nesne kategorisinden biridir. Swift opsiyonları, sendikaları ayıran numaralardır ve herhangi bir Swift kodu için kesinlikle gereklidir.

Bu nedenle, "ayrımcı sendikaların işlevsel programlama ile ilişkilendirildiği" önceliği yanlıştır.

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.