Lite skoj - typ 5DV085 - Programspråk, Department of Computing Science, Umeå University - jem@cs.umu.se
Kommentarer och frågor på sem 1?
Byte av tid Den 26:e - skulle vi kunna flytta den lektionen? Förmiddagen?
Istället för deriving Mer kontroll än deriving vore trevligt Anta data Person = Person{ first::string, last ::String, queuenr :: Int } För att kunna jämföra data Person = Person{ first::string, last ::String, queuenr :: Int } deriving (Eq) Men queuenr är ointressant för jämförelse
a = Person "Kalle" "Anka" 12 b = Person "Knatte" "Anka" 13 c = Person "Kalle" "Anka" 14 > a == b False > a == c False Det är alltså bra om man kan definiera hur t.ex. jämförelse ska ske
Definitionen av typklassen Eq class Eq a where (==) :: a -> a -> Bool (/=) :: a -> a -> Bool x == y = not (x /= y) x /= y = not (x == y) Tänk interface i Java - definition av hur en typ ska uppföra sig, inte själva implementationen. Notera att typen är en parameter Jämförelsen är definierad i sig själv För att få vad jag vill i Person måste jag definiera hur en instans av Eq ser ut för Person
Definiera en instans av Eq för Person instance Eq Person where (Person f1 l1 _) /= (Person f2 l2 _) = f1 /= f2 l1 /= l2 Det är allt == behöver inte definieras eftersom == och /= är definierade i varandra a = Person "Kalle" "Anka" 12 b = Person "Knatte" "Anka" 13 c = Person "Kalle" "Anka" 14 > a == b False > a == c True
Kan också definiera om Show > a Person {first = "Kalle", last = "Anka", queuenr = 12} instance Show Person where show (Person f l q ) = f ++ " " ++ l ++ " in pos " ++ show q > a Kalle Anka in pos 12 > b Knatte Anka in pos 13 > c Kalle Anka in pos 14
Er tur För att kunna jämföra värden så finns funktionen compare definierad för typklassen Ord. Den har signaturen compare :: (Ord a) => a -> a -> Ordering data Ordering = LT EQ GT deriving (Eq, Ord, Bounded, Enum, Read, Show) Definiera en instans av Ord för Person där man jämför baserat på först efternamn och sedan förnamn. Könummer är ointressant > a `compare` b LT > b `compare` a GT > a `compare` c EQ
Möjlig lösning instance Ord Person where compare (Person f1 l1 _ ) (Person f2 l2 _ ) l1 < l2 = LT l1 > l2 = GT f1 < f2 = LT f1 > f2 = GT otherwise = EQ
Subklasser class (Eq a) => Num a where Definition av typklassen Num, där det är ett krav att a implementerar typklassen Eq Dvs det är inget subklassning som vi är vana att tänka utan bara en restriktion på vilken typklass a måste vara
Typen kan vara en typvariabel instance (Eq m) => Eq (Maybe m) where Just x == Just y = x == y Nothing == Nothing = True _ == _ = False Maybe är ju inte någon konkret typ men kan användas som typvariabel Tolkning: Definition av hur jämförelse ska ske för Maybedatatyper Ett krav är att m måste ha jämförelse definierad
Ett steg tillbaka Vad handlar programmering om? Detta är min åsikt Problemlösning Identifiera problemet Lösa problemet Söndra och härska Skriva ner lösningen Abstraktion Många olika sätt Instruktioner - Assembler, högnivåspråk, etc Data - structs, listor, stackar, objekt etc Kod - procedurer, moduler, klasser, paket Vad kod gör - tänk på map, foldr/foldl
Functor En vanlig sak är att mappa från en typ av värden till en annan typ (som ibland är samma typ) Exempel: map - omvandlar från en lista till en annan träd - listor är ju bara degenererade träd Maybe - omvandlar från en värde av typen X till Maybe X Så varför inte flytta upp detta en nivå
functor class Functor f where fmap :: (a -> b) -> f a -> f b f är typkonstruktor, inte en typ fmap tar alltså en funktion som omvandlar från typ a till b, och applicerar detta på något som använder typkonstruktorn f Jämför med map map :: (a -> b) -> [a] -> [b]
> map (+1) [10..15] [11,12,13,14,15,16] instance Functor [] where fmap = map > fmap (+1) [10..15] [11,12,13,14,15,16] instance Functor Maybe where! fmap f (Just x) = Just (f x)! fmap f Nothing = Nothing > fmap (+1) (Just 10) Just 11
Info > :info Int data Int = GHC.Types.I# GHC.Prim.Int#!-- Defined in GHC.Types instance Bounded Int -- Defined in GHC.Enum instance Enum Int -- Defined in GHC.Enum instance Eq Int -- Defined in GHC.Base instance Integral Int -- Defined in GHC.Real instance Num Int -- Defined in GHC.Num instance Ord Int -- Defined in GHC.Base instance Read Int -- Defined in GHC.Read instance Real Int -- Defined in GHC.Real instance Show Int -- Defined in GHC.Show
Uppgift 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 a = treeinsert 10 EmptyTree b = treeinsert 5 a c = treeinsert 20 b d = treeinsert 15 c e = treeinsert 1 d f = treeinsert 3 e g = treeinsert 0 f > show g "Node 10 (Node 5 (Node 1 (Node 0 EmptyTree EmptyTree) (Node 3 EmptyTree EmptyTree)) EmptyTree) (Node 20 (Node 15 EmptyTree EmptyTree) EmptyTree)"
> putstrln (prettyprint g) - 0-1 - 3-5 - 10-15 - 20 -
Möjlig lösning prettyprint x = pp "" x! where! pp indent EmptyTree = indent ++ "-\n"! pp indent (Node x l r ) = (pp (indent ++ " ") l) ++ indent ++ show x ++ "\n" ++ (pp (indent ++ " ") r)