data Pair a = P a a data MultiTuplu a = Nimic | Unul { val :: a } | Pereche { first :: a, second :: a } | Triplu a a a deriving (Show, Read) ---------------------------- -- atenție! Definiție ineficientă (semnatic) în care se suprapun semantic constructorii de date -- Tree constructor de tip unar -- a variabilă de tip data Tree a = Nil | Leaf { value :: a } | Node { value :: a, children :: [Tree a] } myTree = Node "radăcină" [ Node "copil1" [ Leaf "frunză 1", Leaf "frunză 2"], Leaf "frunză 3"] -- arbore binar infinit care în toate nodurile conține numărul 1 treeOnes = Node 1 [treeOnes, treeOnes] -- arbore binar infinit care la BFS dă lista de numere treeB = build 1 where build n = Node n (map build [2*n, 2*n+1]) instance Show a => Show (Tree a) where show tree = pt 0 tree where pt level tree = case tree of Nil -> space level ++ "- \n" Leaf val -> space level ++ show val ++ "\n" Node val children -> space level ++ show val ++ "\n" ++ if all isNil children then "" else concatMap (pt $ level + 1) children space sp = [' ' | _ <- [1..sp * 2]] isNil Nil = True isNil _ = False limit 0 _ = Nil limit level t = case t of Node val children -> Node val $ map (limit (level-1)) children _ -> t preord Nil = [] preord (Leaf v) = [v] preord (Node v children) = v : concatMap preord children ------------ data Graph a = G { edges :: [(a, a)] } graph = G [(1, 2), (1, 3), (1, 4), (2, 1), (2, 2), (2, 7), (4, 6), (6, 4), (6, 3), (6, 7), (6, 8), (5, 2), (5, 6), (5, 9)] outgoing v g = map snd $ filter (\(i,j)->i==v) (edges g) -- sau: -- outgoing v = map snd . (filter $ (== v) . fst) . edges nodes (G []) = [] nodes (G (e:rest)) = -- eNodes ++ filter ((flip notElem) eNodes) (nodes (G rest)) eNodes ++ filter (`notElem` eNodes) (nodes $ G rest) where eNodes = [fst e, snd e] ---------------------------- class Invertible a where invert :: a -> a instance Invertible (Pair a) where invert (P x y) = P y x instance Invertible (MultiTuplu a) where invert mt = case mt of Pereche x y -> Pereche y x Triplu x y z -> Triplu z y x _ -> mt instance Invertible a => Invertible [a] where invert = reverse . map invert instance Invertible (Tree a) where invert (Node v children) = Node v $ invert children invert tree = tree --instance Num a => Invertible a where invert = id instance Invertible Integer where invert = id instance Invertible Bool where invert = not {- limit 5 $ invert treeB -} {-- v1 - este tip ciclic, trebuie ca [x] să fie același lucru cu x class Container a where contents :: a -> [a] instance Container [x] where -- contents [x] = [x] contents = id --} {-- v2 -- ar fi ok în principiu, dar nu poate forța ca tipul x să fie același lucru cu tipul b class Container a where contents :: a -> [b] instance Container [x] where contents = id --} --{-- v3 - corect class Container t where -- a constructor de tip -- Eq a fost necesar pentru contents de la Graph (altfel am fi putut folosi opțiunea InstanceSigs) contents :: Eq b => t b -> [b] --} instance Container [] where contents list = list instance Container Pair where contents (P x y) = [x, y] instance Container MultiTuplu where contents mt = case mt of Nimic -> []; Unul x -> [x]; Pereche x y -> [x, y]; Triplu x y z -> [x, y, z] instance Container Tree where contents = preord instance Container Graph where contents = nodes {- contents . invert $ limit 4 treeB contents graph -} ----------------- --{-- f1 x y z = if x == y then x else z f2 x y = if (invert x) == (invert y) then contents x else contents y f3 x y = if head x > head y then (invert x) ++ (invert y) else [head y - head x] f4 x y z = if x == y then z else if x > y then x else y f5 x y z = if head x > head y then invert z else [invert x, invert y] --} ------------- class TreeLike t where --t constructor de tip makeOne :: a -> t a toTree :: (Show a, Eq a) => (t a) -> Tree a reduce :: (Show a, Eq a) => (a -> [b] -> b) -> (a -> b) -> b -> (t a) -> b reduce fNode fLeaf v0 struct = reduceIt $ toTree struct where reduceIt Nil = v0 reduceIt (Leaf x) = fLeaf x reduceIt (Node x children) = fNode x $ map reduceIt children instance TreeLike Tree where makeOne val = Leaf val toTree = id instance TreeLike Graph where makeOne val = G [(val, val)] toTree g@(G edges) = build [] (head $ nodes g) where build visited gNode = -- consider că visited sunt noduri din graf pentru care am construit deja noduri în arbore (am apelat Node) -- gNode este un nod din graf -- consider că node a fost verificat deja că nu a fost vizitat și acum pot construi un Node cu el Node gNode $ foldl (\ -- iau pe rând succesorii în parcurgere și construiesc arbori pentru fiecare; în arbore, aceștia devin copiii lui gNode previousTrees -- arborii pentru frații anteriori, copii ai lui node successor -- succesor din parcurgere al lui gNode, pentru care construiesc un arbore -> let -- nodurile din graf vizitate în frații (din parcurgere / din arbore) acestui nod visitedInSiblings = concatMap preord previousTrees -- toate nodurile din graf deja vizitate: -- node, -- nodurile vizitate anterior apelului build pentru gNode, -- și nodurile vizitate în frații din parcurgere ai lui gNode visitedAll = gNode : visited ++ visitedInSiblings -- testez dacă am vizitat nodul deja in if successor `elem` visitedAll then previousTrees else previousTrees -- adaug la lista de arbori copii ai lui gNode ++ [build visitedAll successor] -- subarborele pentru acest succesor ) [] (outgoing gNode g) -- toTree vizitează toate nodurile din graf toTreeComplete g = Node (head $ nodes g) $ -- la rădăcina arborelui trebuie să pun o valoare de tipul valorilor din graf -- nu am ce face decât să aleg o valoare oarecare din graf (e.g. valoarea primului nod) foldl (\trees node -> let visited = concatMap preord trees -- nodurile din graf parcurse până acum restrictG (G edges) = -- un graf care conține doar muchii între noduri nevizitate până acum G $ filter (\(i, j) -> i `notElem` visited && j `notElem` visited) $ edges in if node `elem` visited then trees else trees ++ [toTree . restrictG $ g] ) [] $ nodes g