Haskell/Typy definiowane przez użytkownika
Typy definiowane przez użytkownika
[edytuj]Haskell dostarcza trzy sposoby definiowania nowych typów:
- data
- type
- newtype
Mechanizm synonimów (type) został opisany w rozdziale Typy danych. newtype to mechanizm wykorzystywany głownie do optymalizacji. W tym rozdziale przedstawione zostanie wykorzystanie słowa kluczowego data, dzięki któremu możemy definiować struktury oraz typy wyliczeniowe.
Przykład prostego typu wyliczeniowego
[edytuj]Przykładem prostego typu wyliczeniowego może być typ Sygnalizacja opisujący kolory sygnalizacji świetlnej:
data Sygnalizacja = Czerwone | Zolte | Zielone
Sygnalizacja jest tutaj konstruktorem typu, natomiast Czerwone, Zolte i Zielone to konstruktory wartości. Zarówno konstruktor typu, jak i konstruktory wartości w tym przypadku nie przyjmują parametrów.
Typ Sygnalizacja możemy użyć w funkcji coRobic:
coRobic::Sygnalizacja -> String coRobic Czerwone = "Stój" coRobic Zolte = "Uważaj" coRobic Zielone = "Jedź"
Złożone typy definiowane przez użytkownika
[edytuj]Możemy tworzyć bardziej skomplikowane struktury danych, na przykład typ opisujący produkty w sklepie:
data Produkty = Ksiazka String String Int Double --tytul, autor, liczba stron, cena | Gazeta String Int Double --tytuł, numer, cena | Zeszyt Int Double --liczba kartek, cena
Po utworzeni struktury można definiować zmienne typu Produkty. Konstruktor typu Produkty podobnie jak w poprzednim przykładzie nie wymaga podania parametrów, natomiast konstruktory Ksiazka, Gazeta oraz Zeszyt wymagają podania odpowiednich zestawów parametrów (odpowiednich dla każdej wartości)
p1 :: Produkt p1 = Zeszyt 60 2.3 p2 :: Produkt p2 = Gazeta "Ciekawa gazeta" 123 8.5 p3 :: Produkt p3 = Ksiazka "Haskell to fajny jezyk" "Jas Kowalski" 450 70
Ponieważ Książka, Gazeta i Zeszyt są tego samego typu, można utworzyć funkcję, która będzie przyjmowała dowolny Produkt, na przykład funkcję zwracającą opis produktu:
pokazProdukt :: Produkt -> String pokazProdukt (Ksiazka tytul autor l_stron cena) = tytul ++ "; autor: " ++ autor ++ "; " ++ show l_stron ++ " stron; " ++ show cena ++ "PLN" pokazProdukt (Gazeta tytul numer cena) = tytul ++ "; numer: " ++ show numer ++ "; " ++ show cena ++ "PLN" pokazProdukt (Zeszyt l_kartek cena) = "Zeszyt " ++ show l_kartek ++ " kartkowy; " ++ show cena ++ "PLN"
Typy rekursywne
[edytuj]Haskell pozwala na definicję rekursywnych typów danych (takich jak drzewo, kolejka itp.)
data Tree a = Leaf a | Branch (Tree a) (Tree a)
Jest to definicja polimorficznej struktury danych reprezentującej drzewo binarne. Element typu Tree mogą być:
- liśćmi (Leaf) - przechowują wartość typu a
- gałęziami (Branch) - składają się z dwóch innych drzew (które mogą być liśćmi lub innymi gałęziami)
Ponieważ jest to typ polimorficzny, konstruktor tego typu wymaga podania parametru. W tym przypadku jest to typ wartości przechowywanej w liściach drzewa. Również konstruktory Leaf oraz Branch wymagają podania odpowiedniego zestawu parametrów.
Zdefiniujmy teraz funkcję działającą na drzewie. Funkcja ta powinna odczytać wszystkie wartości przechowywane w liściach drzewa i zwrócić je w postaci listy:
fringe :: Tree a -> [a] fringe (Leaf x) = [x] fringe (Branch left right) = fringe left ++ fringe right
Funkcja wywołana z parametrem będącym liściem zwraca listę jednoelementową zawierającą wartość przechowywaną w liściu. Funkcja wywołana z parametrem będącym gałęzią wywołuje rekurencyjnie tą samą funkcję w stosunku do dwóch swoich poddrzew oraz łączy listy uzyskane z tych wywołań.
Ćwiczenie
|