-- tree.hs: conjuring functions over trees -- -- Copyright (C) 2021 Rudy Matela -- Distributed under the 3-Clause BSD licence (see the file LICENSE). {-# LANGUAGE CPP, TemplateHaskell #-} #if __GLASGOW_HASKELL__ == 708 {-# LANGUAGE DeriveDataTypeable, StandaloneDeriving #-} import Data.Typeable (Typeable) #endif import Conjure import Test.LeanCheck import Data.Express hiding (height,size) -- TODO: remove the following import -- and fix build on GHC 7.10 and 7.8 -- the generation of -: and ->>>: somehow fails. import Test.LeanCheck.Utils data Tree = Leaf | Node Tree Int Tree deriving (Eq, Ord, Show, Read) #if __GLASGOW_HASKELL__ == 708 deriving instance Typeable Tree #endif deriveExpress ''Tree unit :: Int -> Tree unit x = Node Leaf x Leaf nil :: Tree -> Bool nil Leaf = True nil _ = False left :: Tree -> Tree left (Node l _ _) = l right :: Tree -> Tree right (Node _ _ r) = r valu :: Tree -> Int valu (Node _ x _) = x leftmost :: Tree -> Int leftmost (Node l x _) = if nil l then x else leftmost (left l) rightmost :: Tree -> Int rightmost (Node _ x r) = if nil r then x else rightmost (right r) height :: Tree -> Int height Leaf = -1 height (Node l _ r) = 1 + max (height l) (height r) size :: Tree -> Int size Leaf = 0 size (Node l _ r) = size l + 1 + size r -- this mem searches both sides of the tree mem :: Int -> Tree -> Bool mem _ Leaf = False mem y (Node l x r) = y == x || mem y l || mem y r insert :: Int -> Tree -> Tree insert x Leaf = unit x insert x (Node l y r) = case compare x y of LT -> Node (insert x l) y r EQ -> Node l y r GT -> Node l y (insert x r) -- TODO: mem alternative for binary search trees instance Listable Tree where tiers = cons0 Leaf \/ cons3 Node instance Name Tree where name _ = "t1" instance Conjurable Tree where conjureExpress = reifyExpress conjureEquality = reifyEquality conjureTiers = reifyTiers conjureSubTypes x = conjureType (undefined :: Int) conjureCases t = [ val (Leaf -: t) , value "Node" (Node ->>>: t) :$ hole l :$ hole x :$ hole r ] where Node l x r = Node undefined undefined undefined -: t main :: IO () main = do conjure "leftmost" leftmost [ prim "undefined" (undefined :: Int) , prim "if" (\p x y -> if p then x else y :: Int) , prim "nil" nil ] conjure "rightmost" rightmost [ prim "undefined" (undefined :: Int) , prim "if" (\p x y -> if p then x else y :: Int) , prim "nil" nil ] conjureWithMaxSize 13 "size" size [ pr (0 :: Int) , pr (1 :: Int) , prim "+" ((+) :: Int -> Int -> Int) , prim "nil" nil , prim "left" left , prim "right" right ] conjureWithMaxSize 13 "height" height [ pr (0 :: Int) , pr (1 :: Int) , pr (-1 :: Int) , prim "+" ((+) :: Int -> Int -> Int) , prim "max" (max :: Int -> Int -> Int) , prim "nil" nil , prim "left" left , prim "right" right ] -- out of reach performance-wise conjure "mem" mem [ pr False , prim "||" (||) , prim "==" ((==) :: Int -> Int -> Bool) ] -- simply out of reach performance-wise (size 34) conjureWithMaxSize 12 "insert" insert [ pr Leaf , prim "Node" Node , prim "==" ((==) :: Int -> Int -> Bool) , prim "<" ((<) :: Int -> Int -> Bool) , prim ">" ((>) :: Int -> Int -> Bool) , prim "if" (\p t1 t2 -> if p then t1 else t2 :: Tree) ] sizeIf :: Tree -> Int sizeIf t = if nil t -- 3 then 0 -- 4 else sizeIf (left t) + sizeIf (right t) -- 5 6 7 8 9 10 11 heightIf :: Tree -> Int heightIf t = if nil t -- 3 then -1 -- 4 else 1 + max (height (left t)) (height (right t)) -- 5 6 7 8 9 10 11 12 13 memIf :: Int -> Tree -> Bool memIf y t = if nil t -- 3 then False -- 4 else y == valu t || memIf y (left t) || memIf y (right t) -- 5 6 7 8 9 10 11 12 13 14 15 16 17 18 insertIf :: Int -> Tree -> Tree insertIf x t = if nil t -- 3 then unit x -- 5 else if x == valu t -- 10 then t -- 11 else if x < valu t -- 16 then Node (insert x (left t)) (valu t) (right t) -- 25 else Node (left t) (valu t) (insert x (right t)) -- 34