{---------------------------------------------------------------    
 Datei mit Beispieldefinitionen zu algebraischen Datenstrukturen
----------------------------------------------------------------}

------------------------
-- Aufzaehlungstypen  --
------------------------

data Tag = Montag | Dienstag | Mittwoch | Donnerstag
           | Freitag | Samstag | Sonntag
	deriving (Eq,Ord,Enum,Show)
        -- Hinweis:
        -- Mittels deriving werden automatisch Grundfunktionen
        -- der genannten Typklassen hergeleitet und bereitgestellt
        -- Eq   --> Gleichheitstest (==) :: Tag -> Tag -> Bool
        -- Ord  --> Vergleichsoperatoren (<) :: Tag -> Tag -> Bool
        -- Enum --> Aufzaehlungsfunktionen enumFromTo :: a -> a -> [a]
        -- Show --> Anzeigefunktion show :: Tag -> String

tagnr :: Tag -> Int
tagnr Montag     = 1
tagnr Dienstag   = 2
tagnr Mittwoch   = 3
tagnr Donnerstag = 4
tagnr Freitag    = 5
tagnr Samstag    = 6
tagnr Sonntag    = 7

nr2tag :: Int -> Tag
nr2tag nr = head [tag | tag <- [Montag .. Sonntag], tagnr tag == nr]


data Farbe = Rot | Gruen | Gelb | Blau
	deriving (Eq,Ord,Enum,Show)

------------------
-- Verbundtypen --
------------------

type Name    = String
type Vorname = String
type Adresse = String
type Alter   = Int

data Person = P Name Vorname Adresse Alter

type Personalliste = [Person]

alter             :: Person -> Alter
alter (P _ _ _ n) =  n

durchschnittsalter    :: Personalliste -> Float
durchschnittsalter [] =  0.0 
durchschnittsalter ps =  fromInt (sumAlter ps) / fromInt (length ps) 
 
sumAlter        :: Personalliste -> Int
sumAlter []     =  0
sumAlter (p:ps) =  alter p + sumAlter ps


------------------
-- Binaerbaeume --
------------------

data BinaryTree a = Leaf a 
		  | Node a (BinaryTree a) (BinaryTree a)
		deriving (Show)

-- typische Baumfunktionen

-- Eintraege inkrementieren
incTree :: BinaryTree Int -> BinaryTree Int
incTree (Leaf x)     = Leaf (x+1)
incTree (Node x l r) = Node (x+1) (incTree l) (incTree r)

-- Eintraege verdoppeln
doubleTree :: BinaryTree Int -> BinaryTree Int
doubleTree (Leaf x)     = Leaf (2*x)
doubleTree (Node x l r) = Node (2*x) (doubleTree l) 
				     (doubleTree r)

-- Eintraege aufsummieren
sumTree :: BinaryTree Int -> Int
sumTree (Leaf x)     = x
sumTree (Node x l r) = x + sumTree l + sumTree r

-- minimalen Eintrag bestimmen
minTree :: BinaryTree Int -> Int
minTree (Leaf x)     = x
minTree (Node x l r) = min x (min (minTree l) (minTree r))

-- Baumtiefe bestimmen
depth :: BinaryTree a -> Int
depth (Leaf _)     = 1
depth (Node x l r) = 1 + max (depth l) (depth r)


--------------------------
-- Geometrische Formen  --
--------------------------

data Shape = Rectangle Side Side
             | Ellipse Radius Radius
             | RtTriangle Side Side
             | Polygon [Vertex]
           deriving Show

type Radius = Float
type Side   = Float
type Vertex  = (Float,Float)



square   :: Side -> Shape
square s =  Rectangle s s

circle   :: Radius -> Shape
circle r =  Ellipse r r


area :: Shape -> Float
area (Rectangle s1 s2)  = s1*s2
area (RtTriangle s1 s2) = s1*s2/2
area (Ellipse r1 r2)  = pi*r1*r2
area (Polygon (v1:vs)) = polyArea vs
      where polyArea           :: [Vertex] -> Float
            polyArea (v2:v3:vs') = triArea v1 v2 v3
                                      + polyArea (v3:vs')
            polyArea _           = 0

triArea         :: Vertex -> Vertex -> Vertex -> Float
triArea v1 v2 v3 = let a = distBetween v1 v2
                       b = distBetween v2 v3
                       c = distBetween v3 v1
                       s = 0.5*(a+b+c)
                   in sqrt (s*(s-a)*(s-b)*(s-c))

-- pi ist vordefiniert
-- pi :: Float  
-- pi = 3.14159


distBetween :: Vertex -> Vertex -> Float
distBetween (x1,y1) (x2,y2) 
   = sqrt ((x1-x2)^2 + (y1-y2)^2)
