Haskell – Moduły
Transkrypt
Haskell – Moduły
Haskell – Moduły Moduł – zestaw powiązanych funkcji, typów, typeclass. Program w Haskellu często jest modułem, który ładuje inne moduły a następnie wykorzystuje zdefiniowane w nich funkcje w celu realizacji postawionego zadania. Haskell dostarcza w postaci modułów bibliotekę funkcji pozwalających np. na: operacje na liczbach zespolonych, operacje na listach, programowanie współbieżne itp. Domyślnie importowany jest moduł Prelude, z którego dotychczas korzystaliśmy. Haskell – Moduły – Ładowanie Załadowanie modułu: import <nazwa modułu> np.: import Data.List Od tego momentu exportowane przez Data.List funkcje itp. są dostępne. Np.: import Data.List numUniques :: (Eq a) => [a] > Int numUniques = length . nub Haskell – Moduły – Ładowanie Używając ghci można załadować moduł poprzez: ghci > :m + Data.List Można również załadować jednocześnie wiele modułów: ghci > :m + Data.List Data.Map Data.Set Funkcje eksportowane przez załadowane w ten sposób moduły dostępne są w globalnej przestrzeni nazw tzn. można się do nich odwoływać przez ich nazwy. Haskell – Moduły – Ładowanie W przypadku potrzeby użycia tylko kilku eksportowanych przez moduł możn użyć formy: z funkcji import Data.List (nub, sort) Spowoduje to, że funkcji nub i sort z modułu Data.List będą dostępne w globalnej przestrzeni nazw. Inną możliwością jest użycie wszystkich funkcji modułu z wyjątkiem wymienionych: import Data.List hiding (nub) W tym przypadku funkcja nub nie będzie dostępna w globalnej przestrzeni nazw. Haskell – Moduły – Ładowanie Użycie formy: import qualified Data.Map Spowoduje, że użycie funkcji eksportowanej przez moduł będzie wymagało wyspecyfikowanie nazwy kwalifikowanej np.: Data.Map.filter Użycie konstrukcji: import qualified Data.Map as M daje możliwość skrócenia zapisu do: M.filter Haskell – Moduły Przydatne moduły: Data.List – operacje na listach Data.Char – operacje na znakach Data.Map – operacje na tablicach asocjacyjnych Data.Set – operacje na zbiorach Haskell – Moduły - Pomoc Aby wyświetlić listę funkcji eksportowanych przez moduł: Prelude> :browse Data.List Można również zastosować: Prelude> :m +Data.List Prelude Data.List> Data.List.<TAB> Display all 112 possibilities? (y or n) Data.List.!! Data.List.foldr1 Data.List.mapAccumR Data.List.tails Data.List.++ Data.List.genericDrop Data.List.maximum Data.List.take Data.List.\\ Data.List.genericIndex Data.List.maximumBy Data.List.takeWhile Haskell – Moduł – Data.List Przykładowe funkcje; transpose – transpozycja listy list ghci > transpose [[1,2,3],[4,5,6], [7,8,9]] [[1,4,7],[2,5,8],[3,6,9]] ghci > transpose ["hey","there","guys"] ["htg","ehu","yey","rs","e"] Haskell – Moduł – Data.List concat – zamiany listy list na listę ghci > concat ["foo","bar","car"] "foobarcar" ghci > concat [[3,4,5],[2,3,4], [2,1,1]] [3,4,5,2,3,4,2,1,1] Haskell – Moduł – Data.List and – przyjmuje listę wartości logicznych jako argument i zwraca True jeśli wszystkie wartości na liście mają wartość True ghci > and $ map (>4) [5,6,7,8] True ghci > and $ map (==4) [4,4,4,3,4] False Podobnie działa or. Haskell – Moduł – Data.List Zamiast or i and w połączniu z map można użyć odpowiednio any i all: ghci > any (==4) [2,3,5,6,1,4] True ghci > all (>4) [6,9,10] True ghci > all (`elem ` ['A'..'Z']) "HEYGUYSwhatsup" False ghci > any (`elem ` ['A'..'Z']) "HEYGUYSwhatsup" True Haskell – Moduł – Data.List iterate przyjmuje jako argument funkcję i wartość startową a następnie przykłada funkcję do wartości startowej po czym do wyniku przykłada funkcję, po czym do wyniku przykłada funkcję itd. Wszystkie wyniki zwraca jako listę nieskończoną: ghci > take 10 $ iterate (*2) 1 [1,2,4,8,16,32,64,128,256,512] ghci > take 3 $ iterate (++ "haha") "haha" ["haha","hahahaha","hahahahahaha"] Haskell – Moduł – Data.List sort – sortuje listę elementów typeclass Ord: ghci > sort [8,5,3,2,1,6,4,2] [1,2,2,3,4,5,6,8] ghci > sort "This will be sorted soon" " Tbdeehiillnooorssstw" Haskell – Moduł – Data.List words dzieli linię tekstu na słowa a unwords tworzy linię tekstu z listy słów: ghci > words "hey these are the words in this sentence" ["hey","these","are","the","words","in","this","sentenc e"] ghci > words "hey these are the words in this\nsentence" ["hey","these","are","the","words","in","this","sentenc e"] ghci > unwords ["hey","there","mate"] "hey there mate" Haskell – Moduł – Data.List nub usuwa z listy duplikaty elementów listy: ghci > nub [1,2,3,4,3,2,1,2,3,4,3,2,1] [1,2,3,4] ghci > nub "Lots of words and stuff" "Lots fwrdanu" Haskell – Moduł – Data.Char Moduł Data.Char zawiera funkcje do operowania na pojedynczych znakach np.: IsAlphaNum zwraca True jeśli argument jest znakiem alfanumerycznym lub False w przeciwnym przypadku: ghci > all isAlphaNum "bobby283" True ghci > all isAlphaNum "eddy the fish!" False Haskell – Moduł – Data.Char Data.Char dostarcza m.in. funkcje toUpper i toLower a także digitToInt i intToDigit: ghci > map digitToInt "34538" [3,4,5,3,8] ghci > map digitToInt "FF85AB" [15,15,8,5,10,11] ghci > intToDigit 15 'f' ghci > intToDigit 5 '5' Haskell – Moduł – Data.Map Moduł Data.Map dostarcza funkcji do przeprowadzania operacji na tablicach asocjacyjnych. Tablice asocjacyjne mogą być reprezentowane jako lista krotek: phoneBook = [("betty","5552938") ,("bonnie","4522928") ,("patsy","4932928") ,("lucille","2052928") ,("wendy","9398282") ,("penny","8532492") ] Haskell – Moduł – Data.Map W module Data.Map używany jest typ Map. Zmienne tego typu można utworzyć np.: Prelude M> let lista = M.fromList [("Zed", 10), ("Ted", 5)] Prelude M> :t lista lista :: M.Map [Char] Integer Haskell – Moduł – Data.Map empty zwraca pustą mapę insert przyjmuje jako parametr klucz, wartość i mapę i zwraca nową mapę z wstawionym kluczem i wartością: ghci > Map.empty fromList [] ghci > Map.insert 3 100 Map.empty fromList [(3,100)] Haskell – Moduł – Data.Map lookup przyjmuje jako argument klucz i listę i zwraca Just wartość jeżeli dla klucza istnieje wartość lub Nothing jeżeli nie znajdzie klucza. Prelude M> M.lookup "Ted" lista Just 5 member jako argumenty przyjmuje klucz i mapę i zwraca informację czy dla klucza istnieje wartość: ghci > Map.member 3 $ Map.fromList [(3,6),(4,3),(6,9)] True ghci > Map.member 3 $ Map.fromList [(2,5),(4,5)] False Haskell – Moduł – Data.Set Moduł Data.Set oferuje operacje na zbiorach. Zbiory podobnie jak mapy tworzone są z list np.: Prelude> import qualified Data.Set as Set Prelude Set> let setA = Set.fromList [ 1, 2, 3] Prelude Set> let setB = Set.fromList [ 3, 4, 5] Prelude Set> :t setA setA :: Set.Set Integer Haskell – Moduł – Data.Set Na zbiorach możliwe są typowe dla zbiorów operacje jak intersection, difference: Prelude Set> Set.intersection setA setB fromList [3] Prelude Set> Set.difference setA setB FromList [1,2] Prelude Set> Set.union setA setB fromList [1,2,3,4,5] Haskell – Moduły – Tworzenie Aby utworzyć własny moduł np. zawierajacy funkcje zwiazane z geometrią należy utworzyć plik .hs (np.: Geometry.hs) zawierający nagłowek opisujący jakie funkcje moduł eksportuje (udostępnia): module Geometry ( sphereVolume , sphereArea , cubeVolume ) where Haskell – Moduły – Tworzenie Po czym następują definicje funkcji np.: sphereVolume :: Float > Float sphereVolume radius = (4.0 / 3.0) * pi * (radius ^ 3) sphereArea :: Float > Float sphereArea radius = 4 * pi * (radius ^ 2) Haskell – Moduły – Tworzenie Własnego modułu można użyć tak jak modułów dostarczanych standardowo: ghci> import Geometry Haskell – Moduły – Tworzenie Moduły mogą być tworzone jako konstrukcje hierarchiczne. Każdy moduł może zawierać podmoduły. Moduł Geometry może zostać przedstawiony jako zawierający podmoduły dla różnych rodzajów obiektów. Należy utworzyć katalog Geometry zawierający pliki sphere.hs, cuboid.hs and cube.hs. Haskell – Moduły – Tworzenie sphere.hs module Geometry.Sphere ( volume , area ) where volume :: Float > Float volume radius = (4.0 / 3.0) * pi * (radius ^ 3) area :: Float > Float area radius = 4 * pi * (radius ^ 2) Haskell – Moduły – Tworzenie cuboid.hs module Geometry.Cuboid ( volume , area ) where volume :: Float > Float > Float > Float volume a b c = rectangleArea a b * c area :: Float > Float > Float > Float area a b c = rectangleArea a b * 2 + rectangleArea a c * 2 + rectangleArea c b * 2 rectangleArea :: Float > Float > Float rectangleArea a b = a * b Haskell – Moduły – Tworzenie cube.hs module Geometry.Cube ( volume , area ) where import qualified Geometry.Cuboid as Cuboid volume :: Float > Float volume side = Cuboid.volume side side side area :: Float > Float area side = Cuboid.area side side side Haskell – Moduły – Tworzenie Użycie takiego modułu: import Geometry.Sphere Teraz można użyć area i volume do wyliczenia pola i objętości kuli. Można również wykonać: import qualified Geometry.Sphere as Sphere import qualified Geometry.Cuboid as Cuboid import qualified Geometry.Cube as Cube Można wtedy wywołać: Sphere.area, Sphere.volume itd. do obliczenia pola powierzchni i objętości odpowiednich obiektów.