Haskell/Typy definiowane przez użytkownika
Typy definiowane przez użytkownika
edytujHaskell 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
edytujPrzykł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
edytujMoż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
edytujHaskell 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
|