Haskell forts 5DV085 - Programspråk, Department of Computing Science, Umeå University - jem@cs.umu.se
Moduler Grupp 1, Department of Computing Science, Umeå University - jem@cs.umu.se
Function application operator $ Normalt så är f a b c d samma som (((f a) b) c) d Men f $ a b c d blir f (((a b) c) d)
Function composition Sätta ihop två funktioner - dvs ut från en funktion är in till en annan. Om vi har a. b så betyder det egentligen a (b x) Om vi tittar på typsignaturen (b -> c) -> (a -> b) -> a -> c Exempel map (\xs -> negate (sum (tail xs))) [[1..5],[3..6],[1..7]] [-14,-15,-27] map (negate. sum. tail) [[1..5],[3..6],[1..7]]
Datatyper en start Det är naturligtvis möjligt att definiera egna datatyper data Bodies = Sphere Float Box Float Float Float > let z = Box 5 2 3 > z <interactive>:1:0: No instance for (Show Bodies)... data Bodies = Sphere Float Box Float Float Float! deriving (Show) > z Box 5.0 2.0 3.0
Datatyper en start surface (Sphere r) = 4 * pi * r^2 surface (Box b d h) = 2 * (b*d + b*h + d*h) volume (Sphere r) = 4 * pi * r^3 / 3 volume (Box b d h) = b * d * h > surface z 62.0 > volume z 30.0
Datatyper en start surface (Sphere r) = 4 * pi * r^2 surface (Box b d h) = 2 * (b*d + b*h + d*h) volume (Sphere r) = 4 * pi * r^3 / 3 volume (Box b d h) = b * d * h > surface z 62.0 > volume z 30.0
Konstruktorerna är funktioner! > map (Box 4 5) [1..5] [Box 4.0 5.0 1.0, Box 4.0 5.0 2.0, Box 4.0 5.0 3.0, Box 4.0 5.0 4.0, Box 4.0 5.0 5.0]
Egna datatyper i egen definition Det är naturligtvis möjligt att använda egendefinierade datatyper när jag definierar nya data Point3D = Point3D Float Float Float deriving (Show) data Bodies = Sphere Float Point3D Box Float Float Float Point3D deriving (Show) > let curpos = Point3D 20 10 12 > let sph = Sphere 12 curpos > sph Sphere 12.0 (Point3D 20.0 10.0 12.0) surface (Sphere r _) = 4 * pi * r--2 surface (Box b d h _) = 2 * (b*d + b*h + d*h) distance (Point3D x y z) = sqrt(x^2+y^2+z^2) bodydistance (Sphere _ p) = distance(p) bodydistance (Box _ p) = distance(p) > bodydistance sph 25.377155
Records Det blir lite bökigt att i längden hålla reda på positionen för olika delar av definitionen data Point3D = Point3D{! xcoord::float,! ycoord::float,! zcoord::float}! deriving (Show) > let curpos = Point3D 20 10 12 > curpos Point3D {xcoord = 20.0, ycoord = 10.0, zcoord = 12.0} > ycoord curpos 10.0 > zcoord curpos 12.0
data Bodies = Sphere { radius::float, position::point3d } Box { width::float, depth::float, height::float, position::point3d } distance (Point3D x y z) = sqrt(x^2+y^2+z^2) bodydistance (Sphere _ p) = distance(p) bodydistance (Box _ p) = distance(p)
Type parameters Istället för att definiera en datatyp med en specifik typ så kan jag välja att definiera en mer generell variant (exempel från boken) data Maybe a = Nothing Just a > Just 5 Just 5 > :t Just 5 Just 5 :: (Num t) => Maybe t > :t Just 5.0 Just 5.0 :: (Fractional t) => Maybe t > :t Just (5.0::Float) Just (5.0::Float) :: Maybe Float > :t Just "Hello" Just "Hello" :: Maybe [Char]
data Car = Car { company :: String, model :: String, year :: Int } deriving (Show) data Car a b c = Car { company :: a, model :: b, data Car a b c = Car { year :: c company :: String, } deriving (Show) model :: String, year :: c } deriving (Show) tellcar (Car {company = c, model = m, year = y}) =! "This " ++ c ++ " " ++ m ++ " was made " ++ show y > let car1 = Car "Volvo" "Amazon" 1964 > :t car1 car1 :: Car a b Integer > tellcar car1 "This Volvo Amazon was made 1964" > let car2 = Car "Volvo" "PV444" "ca 1955" > tellcar car2 "This Volvo PV444 was made "ca 1955""
Derived instances Type classes definierar något slags beteende Hur kan man få en klass att få ett beteende data Person = Person{ firstname :: String, lastname :: String, age :: Int } deriving (Eq) > let a = Person "Kalle" "Anka" 62 > let b = Person "Knatte" "Anka" 41 > a == b False > let c = Person "Kalle" "Anka" 62 > a == c True Funkar även för show och read
Ordnade datatyper data Day = Monday Tuesday Wednesday Thursday Friday Saturday Sunday data Day = Monday Tuesday Wednesday Thursday Friday Saturday Sunday deriving (Eq, Ord, Show, Read, Bounded, Enum) > Saturday == Sunday False > Saturday == Saturday True > Saturday > Friday True > Monday `compare` Wednesday LT > succ Monday Tuesday > [Thursday.. Sunday] [Thursday,Friday,Saturday,Sunday]
Synonymer För att göra det enklare att läsa koden. alias för olika typer type String = [Char] Exempel på hur man kan utnyttja det (från boken)
phonebook :: [(String, String)] phonebook = [("betty", "555-2938"),("bonnie", "452-2928"),("patsy", "493-2928"),("lucille", "205-2928"),("wendy", "939-8282"),("penny", "853-2492") ] type PhoneNumber = String type Name = String type PhoneBook = [(Name, PhoneNumber)] inphonebook :: Name -> PhoneNumber -> PhoneBook -> Bool inphonebook name pnumber pbook = (name, pnumber) `elem` pbook inphonebook :: String -> String -> [(String, String)] -> Bool
Rekursiva datatyper Datatyper som är definierade i sig själva är inget nytt. Tar samma exempel som boken Ett sätt att se på listor är en array (vilket inte är en lista), dvs traditionellt en minnesutrymme indelat i fack som man kan adressera En vidare utveckling i detta tankesätt är listor. Dessa kan man endera se som dynamiska arrayer (inget bra sätt) eller på ett mer abstrakt sätt
Listor är rekursiva I Haskell (och många andra språk) så är det möjligt att definiera rekursiva datatyper Basfallet: Tom lista Annars: Ett huvud och en lista Med andra ord:
data MinLista a = Tom Ihop a (MinLista a) deriving (Show, Read, Eq, Ord) > let a = Tom > :t a a :: MinLista a > let b = 118 `Ihop` a > b Ihop 118 Tom > :t b b :: MinLista Integer > let c = 42 `Ihop` b > c Ihop 42 (Ihop 118 Tom) > :t c c :: MinLista Integer
Definiera infix operatorer infixr 5 :-: data MinLista a = Tom a :-: (MinLista a) deriving (Show, Read, Eq, Ord) > let c = 42 :-: 118 :-: Tom > c 42 :-: (118 :-: Tom) infix 5 ^++ (^++) :: MinLista a -> MinLista a -> MinLista a Tom ^++ bl = bl (a :-: al) ^++ bl = a :-: (al ^++ bl) > let d = 1 :-: 2 :-: Tom > let e = c ^++ d > e 42 :-: (118 :-: (1 :-: (2 :-: Tom)))
Träd är också rekursiva data Tree a = EmptyTree Node a (Tree a) (Tree a) deriving (Show) treeinsert::(ord a) => a -> Tree a -> Tree a treeinsert aval EmptyTree = Node aval EmptyTree EmptyTree treeinsert aval (Node bval ltree rtree) aval > bval = Node bval ltree (treeinsert aval rtree) otherwise = Node bval (treeinsert aval ltree) rtree > let a = treeinsert 12 EmptyTree > a Node 12 EmptyTree EmptyTree > let b = treeinsert 6 a > b Node 12 (Node 6 EmptyTree EmptyTree) EmptyTree > let c = treeinsert 24 b > let d = treeinsert 114 c > d Node 12 (Node 6 EmptyTree EmptyTree) (Node 24 EmptyTree (Node 114 EmptyTree EmptyTree)) > let e = treeinsert 24 d > e Node 12 (Node 6 EmptyTree EmptyTree) (Node 24 (Node 24 EmptyTree EmptyTree) (Node 114 EmptyTree EmptyTree))