Bir databildirimde, bir tür kurucusu eşittir işaretinin sol tarafındaki şeydir. Veri yapıcı (lar) eşittir işareti sağ taraftaki şeylerdir. Bir türün beklendiği yerde tür oluşturucuları ve bir değerin beklendiği durumlarda veri oluşturucularını kullanırsınız.
Veri oluşturucular
İşleri basitleştirmek için, bir rengi temsil eden bir tür örneği ile başlayabiliriz.
data Colour = Red | Green | Blue
Burada üç veri oluşturucumuz var. Colourbir tür ve bir tür Greendeğeri içeren bir yapıcıdır Colour. Benzer şekilde Redve Blueher ikisi de tür değerleri oluşturan yapıcılardır Colour. Yine de onu baharatlandırmayı hayal edebiliriz!
data Colour = RGB Int Int Int
Halen sadece türe sahibiz Colour, ancak RGBbir değer değil - bu, üç İnç alan ve bir değer döndüren bir fonksiyondur ! RGBtürü var
RGB :: Int -> Int -> Int -> Colour
RGBbazı değerleri bağımsız değişkenleri olarak alan ve daha sonra bunları yeni bir değer oluşturmak için kullanan bir veri yapıcısıdır . Herhangi bir nesne tabanlı programlama yaptıysanız, bunu anlamalısınız. OOP'de, kurucular bazı değerleri bağımsız değişken olarak alır ve yeni bir değer döndürür!
Bu durumda RGBüç değere uygularsak bir renk değeri elde ederiz!
Prelude> RGB 12 92 27
#0c5c1b
Biz bir değer inşa Çeşidi Colourveri kurucu uygulayarak. Bir veri yapıcısı, bir değişkenin yapacağı gibi bir değer içerir veya argümanı olarak başka değerleri alır ve yeni bir değer oluşturur . Daha önce programlama yaptıysanız, bu kavram size çok garip gelmemelidir.
perde arası
'Leri depolamak için bir ikili ağaç oluşturmak Stringistiyorsanız, şöyle bir şey yapmayı hayal edebilirsiniz:
data SBTree = Leaf String
| Branch String SBTree SBTree
Burada gördüğümüz SBTree, iki veri yapıcısı içeren bir türdür . Başka bir deyişle, türün değerlerini oluşturacak iki işlev vardır (yani Leafve Branch) SBTree. İkili ağaçların nasıl çalıştığına aşina değilseniz, orada kalın. Aslında ikili ağaçların nasıl çalıştığını bilmenize gerek yok, sadece bu ağaçların bir şekilde depolandığını String.
Ayrıca her iki veri yapıcısının da bir Stringargüman aldığını görüyoruz - bu ağaçta saklayacakları String.
Fakat! Ya biz de depolayabilmek Boolistiyorsak, yeni bir ikili ağaç oluşturmalıyız. Şunun gibi görünebilir:
data BBTree = Leaf Bool
| Branch Bool BBTree BBTree
Tip oluşturucular
Her ikisi de SBTreeve BBTreetür oluşturuculardır. Ama göze batan bir sorun var. Ne kadar benzer olduklarını görüyor musun? Bu, bir yerde gerçekten bir parametre istediğinizi gösteren bir işarettir.
Böylece bunu yapabiliriz:
data BTree a = Leaf a
| Branch a (BTree a) (BTree a)
Şimdi tür yapıcısına parametre olarak bir tür değişkeni a ekliyoruz. Bu beyanda BTreebir fonksiyon haline gelmiştir. Bir türü argüman olarak alır ve yeni bir tür döndürür .
Bir arasındaki farkı dikkate almak burada önemli olan beton türü (örnekler Int, [Char]ve Maybe Bool) programınızda bir değere atanabilir türüdür ve hangi tip yapıcı işlevi Bir tipin beslemek gerekir olmaya muktedir bir değere atanmış. Bir değer asla "liste" türünde olamaz çünkü "bir şeylerin listesi " olması gerekir. Aynı ruhla, bir değer asla "ikili ağaç" tipinde olamaz, çünkü "bir şeyi depolayan ikili ağaç " olması gerekir.
Örneğin, Boolbir argüman olarak BTreeiletirsek, s'yi BTree Booldepolayan ikili ağaç olan türü döndürür Bool. Tipi değişken her geçtiği yerini atürüyle Boolve bu doğru nasıl kendiniz görebilirsiniz.
İsterseniz BTree, tür ile bir işlev olarak görüntüleyebilirsiniz .
BTree :: * -> *
Türler bir şekilde türlere benzer - *somut bir türü belirtir, bu yüzden somut bir türden somut bir türe olduğunu söylüyoruz BTree.
Sarmak
Bir an geri gelin ve benzerlikleri not edin.
Bir veri yapıcı 0 veya daha fazla süren bir "işlev" olduğu değerleri ve yeni bir değer size geri verir.
Bir tür kurucusu , 0 veya daha fazla türü alan ve size yeni bir türü geri veren bir "işlev" dir .
Değerlerimizde küçük değişiklikler istiyorsak, parametrelere sahip veri oluşturucular harikadır - bu varyasyonları parametrelere koyarız ve değeri yaratan kişinin hangi argümanları koyacağına karar vermesine izin veririz. Aynı anlamda, parametrelere sahip yazım oluşturucular da iyidir. türlerimizde küçük değişiklikler istiyorsak! Bu varyasyonları parametre olarak koyarız ve türü yaratan kişinin hangi argümanları koyacağına karar vermesine izin veririz.
Bir vaka çalışması
Burada ev gerginliği olarak, Maybe atürünü düşünebiliriz . Tanımı
data Maybe a = Nothing
| Just a
Burada, Maybesomut bir tür döndüren bir tür oluşturucu. Justbir değer döndüren bir veri yapıcısıdır. Nothingbir değer içeren bir veri yapıcısıdır. Türüne bakarsak Just, görürüz
Just :: a -> Maybe a
Başka bir deyişle, Justbir tür değeri alır ave bir tür değeri döndürür Maybe a. Türüne bakarsak Maybe, bunu görürüz
Maybe :: * -> *
Başka bir deyişle, Maybesomut bir türü alır ve somut bir türü döndürür.
Bir kere daha! Somut bir tür ve bir tür yapıcı işlevi arasındaki fark. Bir Maybes listesi oluşturamazsınız - eğer yürütmeye çalışırsanız
[] :: [Maybe]
bir hata alırsınız. Ancak Maybe Int, bir veya listesi oluşturabilirsiniz Maybe a. Bunun nedeni Maybe, bir tür yapıcı işlev olmasıdır, ancak bir listenin somut türde değerler içermesi gerekir. Maybe Intve Maybe asomut türlerdir (veya isterseniz, somut türleri döndüren yapıcı işlevlerini yazma çağrıları.)
Car, çünkü hem bir tür oluşturucu (sol tarafında=) hem de bir veri oluşturucu (sağ tarafta). İlk örnekte,Cartür yapıcısı hiçbir argüman almaz, ikinci örnekte ise üç tane alır. Her iki örnekte de,Carveri yapıcısı üç argüman alır (ancak bu argümanların türleri bir durumda sabit, diğerinde parametreleştirilmiştir).