Bir data
bildirimde, 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. Colour
bir tür ve bir tür Green
değeri içeren bir yapıcıdır Colour
. Benzer şekilde Red
ve Blue
her 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 RGB
bir değer değil - bu, üç İnç alan ve bir değer döndüren bir fonksiyondur ! RGB
türü var
RGB :: Int -> Int -> Int -> Colour
RGB
bazı 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 Colour
veri 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 String
istiyorsanı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 Leaf
ve 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 String
argüman aldığını görüyoruz - bu ağaçta saklayacakları String.
Fakat! Ya biz de depolayabilmek Bool
istiyorsak, 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 SBTree
ve BBTree
tü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 BTree
bir 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, Bool
bir argüman olarak BTree
iletirsek, s'yi BTree Bool
depolayan ikili ağaç olan türü döndürür Bool
. Tipi değişken her geçtiği yerini a
türüyle Bool
ve 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 a
türünü düşünebiliriz . Tanımı
data Maybe a = Nothing
| Just a
Burada, Maybe
somut bir tür döndüren bir tür oluşturucu. Just
bir değer döndüren bir veri yapıcısıdır. Nothing
bir 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, Just
bir tür değeri alır a
ve 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, Maybe
somut 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 Maybe
s 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 Int
ve Maybe a
somut 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,Car
tür yapıcısı hiçbir argüman almaz, ikinci örnekte ise üç tane alır. Her iki örnekte de,Car
veri yapıcısı üç argüman alır (ancak bu argümanların türleri bir durumda sabit, diğerinde parametreleştirilmiştir).