У dataдекларації конструктором типу є річ з лівої сторони знака рівності. Конструктор (s) дані речі на правій стороні від знака рівності. Ви використовуєте конструктори типів там, де очікується тип, і ви використовуєте конструктори даних там, де очікується значення.
Конструктори даних
Щоб зробити прості речі, ми можемо почати з прикладу типу, який представляє колір.
data Colour = Red | Green | Blue
Тут ми маємо три конструктори даних. Colourє типом і Greenє конструктором, який містить значення типу Colour. Аналогічно Redі Blueобидва конструктори, які будують значення типу Colour. Ми могли б уявити, як це спекулює!
data Colour = RGB Int Int Int
У нас ще є лише тип Colour, але RGBце не значення - це функція, яка бере три Інти і повертає значення! RGBмає тип
RGB :: Int -> Int -> Int -> Colour
RGB- це конструктор даних, який є функцією, яка приймає деякі значення в якості аргументів, а потім використовує ці для побудови нового значення. Якщо ви виконали будь-яке об'єктно-орієнтоване програмування, вам слід визнати це. В OOP конструктори також приймають деякі значення як аргументи і повертають нове значення!
У цьому випадку, якщо застосувати RGBдо трьох значень, ми отримаємо значення кольору!
Prelude> RGB 12 92 27
#0c5c1b
Ми побудували значення типу Colour, застосувавши конструктор даних. Конструктор даних або містить значення, подібне до змінної, або приймає інші значення в якості аргументу і створює нове значення . Якщо ви раніше займалися програмуванням, ця концепція вам не повинна бути дуже дивною.
Антракт
Якщо ви хочете побудувати бінарне дерево для зберігання Strings, ви можете уявити собі щось подібне
data SBTree = Leaf String
| Branch String SBTree SBTree
Тут ми бачимо тип, SBTreeякий містить два конструктори даних. Іншими словами, є дві функції (а саме Leafі Branch), які будують значення SBTreeтипу. Якщо ви не знайомі з тим, як працюють двійкові дерева, просто повісьте там. Вам насправді не потрібно знати, як працюють бінарні дерева, лише те, що це зберігає Stringпевний шлях.
Ми також бачимо, що обидва конструктори даних беруть Stringаргументи - це рядок, який вони збираються зберігати у дереві.
Але! Що, якби ми також хотіли вміти зберігати Bool, нам довелося б створити нове бінарне дерево. Це могло виглядати приблизно так:
data BBTree = Leaf Bool
| Branch Bool BBTree BBTree
Тип конструкторів
І те, SBTreeі BBTreeконструктори типу. Але є яскрава проблема. Ви бачите, наскільки вони схожі? Це знак того, що ви дійсно хочете десь параметр.
Тож ми можемо це зробити:
data BTree a = Leaf a
| Branch a (BTree a) (BTree a)
Тепер ми вводимо змінну типу a як параметр конструктору типів. У цій декларації BTreeстало функцією. Він бере свій тип як аргумент і повертає новий тип .
Тут важливо враховувати різницю між типом бетону (приклади включають в себе Int, [Char]а Maybe Bool) , який є типом , який може бути віднесений до значення в вашій програмі, а функція конструктора типу , який вам потрібно годувати тип , щоб мати можливість бути присвоєне значення. Значення ніколи не може бути типу "список", оскільки воно повинно бути "списком чогось ". У тому ж дусі значення ніколи не може бути типу "бінарне дерево", оскільки воно повинно бути "бінарним деревом, яке щось зберігає ".
Якщо ми передамо, скажімо, Boolяк аргумент BTree, він повертає тип BTree Bool, який є бінарним деревом, яке зберігає Bools. Замініть кожне виникнення змінної типу aна тип Bool, і ви зможете самі переконатися, як це правда.
Якщо ви хочете, ви можете розглядати BTreeяк функцію з родом
BTree :: * -> *
Види дещо схожі на типи - *вказує на конкретний тип, тому ми говоримо BTree, що від конкретного типу до конкретного типу.
Підведенню
Відійдіть мить сюди і відзначте подібність.
Конструктор даних є «функцією» , яка приймає 0 або більше значень і дає Вам нове значення.
Конструктор типу є «функцією» , яка приймає 0 або більше типів і дає Вам новий тип.
Конструктори даних з параметрами круті, якщо ми хочемо незначних змін у наших значеннях - ми ставимо ці зміни параметрів і даємо хлопцеві, який створює значення, вирішувати, які аргументи вони збираються вносити. У цьому ж сенсі типи конструкторів з параметрами класні якщо ми хочемо невеликих варіацій у наших типах! Ми ставимо ці варіанти як параметри і даємо хлопцеві, який створює тип, вирішувати, які аргументи вони збираються викласти.
Тематичне дослідження
Оскільки тут розтягується будинок, ми можемо розглянути Maybe aтип. Його визначення таке
data Maybe a = Nothing
| Just a
Тут Maybeзнаходиться конструктор типу, який повертає конкретний тип. Just- конструктор даних, який повертає значення. Nothing- конструктор даних, який містить значення. Якщо ми подивимось на тип Just, ми це бачимо
Just :: a -> Maybe a
Іншими словами, Justприймає значення типу aі повертає значення типу Maybe a. Якщо ми дивимось на вид Maybe, ми це бачимо
Maybe :: * -> *
Іншими словами, Maybeприймає конкретний тип і повертає конкретний тип.
Знову! Різниця між типом бетону та конструктором типу. Ви не можете створити список Maybes - якщо ви намагаєтеся виконати
[] :: [Maybe]
ви отримаєте помилку Однак ви можете створити список Maybe Int, або Maybe a. Це тому Maybe, що це функція конструктора типів, але список повинен містити значення конкретного типу. Maybe Intі Maybe aце конкретні типи (або, якщо ви хочете, дзвінки вводити функції конструктора, які повертають конкретні типи.)
Carце конструктор типу (з лівого боку=) та конструктор даних (праворуч). У першому прикладіCarконструктор типу не бере аргументів, у другому прикладі - три. В обох прикладахCarконструктор даних приймає три аргументи (але типи цих аргументів в одному випадку виправлені, а в іншому параметризовані).