ral-0.2.2: src/Data/RAVec/Tree/DF.hs
{-# LANGUAGE CPP #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE Safe #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
-- | Depth indexed perfect tree as data family.
module Data.RAVec.Tree.DF (
Tree (..),
-- * Construction
singleton,
-- * Conversions
toList,
reverse,
-- * Indexing
(!),
tabulate,
leftmost,
rightmost,
-- * Folds
foldMap,
foldMap1,
ifoldMap,
ifoldMap1,
foldr,
ifoldr,
foldr1Map,
ifoldr1Map,
foldl,
ifoldl,
-- * Special folds
length,
null,
sum,
product,
-- * Mapping
map,
imap,
traverse,
itraverse,
#ifdef MIN_VERSION_semigroupoids
traverse1,
itraverse1,
#endif
itraverse_,
-- * Zipping
zipWith,
izipWith,
repeat,
-- * Universe
universe,
-- * QuickCheck
liftArbitrary,
liftShrink,
-- * Ensure spine
ensureSpine,
) where
import Prelude
(Bool (..), Eq (..), Functor (..), Int, Num, Ord (..), Ordering (..),
Show (..), ShowS, flip, id, seq, showChar, showParen, showString,
uncurry, ($), (&&), (*), (+), (.))
import Control.Applicative (Applicative (..), liftA2, (<$>))
import Control.DeepSeq (NFData (..))
import Control.Monad (void)
import Data.Hashable (Hashable (..))
import Data.Monoid (Monoid (..))
import Data.Nat (Nat (..))
import Data.Semigroup (Semigroup (..))
import Data.Wrd (Wrd (..))
import qualified Data.Type.Nat as N
-- instances
import qualified Data.Foldable as I (Foldable (..))
import qualified Data.Traversable as I (Traversable (..))
import qualified Test.QuickCheck as QC
import qualified Data.Foldable.WithIndex as WI (FoldableWithIndex (..))
import qualified Data.Functor.WithIndex as WI (FunctorWithIndex (..))
import qualified Data.Traversable.WithIndex as WI (TraversableWithIndex (..))
#ifdef MIN_VERSION_distributive
import qualified Data.Distributive as I (Distributive (..))
#ifdef MIN_VERSION_adjunctions
import qualified Data.Functor.Rep as I (Representable (..))
#endif
#endif
#ifdef MIN_VERSION_semigroupoids
import Data.Functor.Apply (Apply (..))
import qualified Data.Semigroup.Foldable as I (Foldable1 (..))
import qualified Data.Semigroup.Traversable as I (Traversable1 (..))
#endif
-- $setup
-- >>> :set -XScopedTypeVariables
-- >>> import Data.Proxy (Proxy (..))
-- >>> import Prelude (Char, not, uncurry, flip, error, ($), Bool (..), id)
-- >>> import Data.Wrd (Wrd (..))
-- >>> import qualified Data.Type.Nat as N
-------------------------------------------------------------------------------
-- Types
-------------------------------------------------------------------------------
data family Tree (n :: Nat) a
newtype instance Tree 'Z a = Leaf a
data instance Tree ('S n) a = Node (Tree n a) (Tree n a)
-------------------------------------------------------------------------------
-- Instances
-------------------------------------------------------------------------------
instance (Eq a, N.SNatI n) => Eq (Tree n a) where
(==) = getEqual (N.induction1 start step) where
start :: Equal 'Z a
start = Equal $ \(Leaf x) (Leaf y) -> x == y
step :: Equal m a -> Equal ('S m) a
step (Equal go) = Equal $ \(Node x1 y1) (Node x2 y2) ->
go x1 x2 && go y1 y2
newtype Equal n a = Equal { getEqual :: Tree n a -> Tree n a -> Bool }
instance (Ord a, N.SNatI n) => Ord (Tree n a) where
compare = getCompare (N.induction1 start step) where
start :: Compare 'Z a
start = Compare $ \(Leaf x) (Leaf y) -> compare x y
step :: Compare m a -> Compare ('S m) a
step (Compare go) = Compare $ \(Node x1 y1) (Node x2 y2) ->
go x1 x2 <> go y1 y2
newtype Compare n a = Compare { getCompare :: Tree n a -> Tree n a -> Ordering }
instance (Show a, N.SNatI n) => Show (Tree n a) where
showsPrec = getShowsPrec (N.induction1 start step) where
start :: ShowsPrec 'Z a
start = ShowsPrec $ \d (Leaf x) -> showParen (d > 10)
$ showString "Leaf "
. showsPrec 11 x
step :: ShowsPrec m a -> ShowsPrec ('S m) a
step (ShowsPrec go) = ShowsPrec $ \d (Node x y) -> showParen (d > 10)
$ showString "Node "
. go 11 x
. showChar ' '
. go 11 y
newtype ShowsPrec n a = ShowsPrec { getShowsPrec :: Int -> Tree n a -> ShowS }
instance N.SNatI n => Functor (Tree n) where
fmap = map
instance N.SNatI n => I.Foldable (Tree n) where
foldMap = foldMap
foldr = foldr
-- foldl' = foldl'
null = null
length = length
sum = sum
product = product
#ifdef MIN_VERSION_semigroupoids
instance (N.SNatI n) => I.Foldable1 (Tree n) where
foldMap1 = foldMap1
instance (N.SNatI n) => I.Traversable1 (Tree n) where
traverse1 = traverse1
#endif
instance N.SNatI n => I.Traversable (Tree n) where
traverse = traverse
-- | @since 0.2
instance N.SNatI n => WI.FunctorWithIndex (Wrd n) (Tree n) where
imap = imap
-- | @since 0.2
instance N.SNatI n => WI.FoldableWithIndex (Wrd n) (Tree n) where
ifoldMap = ifoldMap
ifoldr = ifoldr
-- | @since 0.2
instance N.SNatI n => WI.TraversableWithIndex (Wrd n) (Tree n) where
itraverse = itraverse
instance (NFData a, N.SNatI n) => NFData (Tree n a) where
rnf = getRnf (N.induction1 z s) where
z = Rnf $ \(Leaf x) -> rnf x
s (Rnf rec) = Rnf $ \(Node x y) -> rec x `seq` rec y
newtype Rnf n a = Rnf { getRnf :: Tree n a -> () }
instance (Hashable a, N.SNatI n) => Hashable (Tree n a) where
hashWithSalt = getHashWithSalt (N.induction1 z s) where
z = HashWithSalt $ \salt (Leaf x) -> salt `hashWithSalt` x
s (HashWithSalt rec) = HashWithSalt $ \salt (Node x y) -> rec (rec salt x) y
newtype HashWithSalt n a = HashWithSalt { getHashWithSalt :: Int -> Tree n a -> Int }
instance N.SNatI n => Applicative (Tree n) where
pure = repeat
(<*>) = zipWith ($)
_ *> x = x
x <* _ = x
liftA2 = zipWith
-- TODO: Monad
#ifdef MIN_VERSION_distributive
instance N.SNatI n => I.Distributive (Tree n) where
distribute f = tabulate (\k -> fmap (! k) f)
#ifdef MIN_VERSION_adjunctions
instance N.SNatI n => I.Representable (Tree n) where
type Rep (Tree n) = Wrd n
tabulate = tabulate
index = (!)
#endif
#endif
instance (Semigroup a, N.SNatI n) => Semigroup (Tree n a) where
(<>) = zipWith (<>)
instance (Monoid a, N.SNatI n) => Monoid (Tree n a) where
mempty = pure mempty
mappend = zipWith mappend
#ifdef MIN_VERSION_semigroupoids
instance N.SNatI n => Apply (Tree n) where
(<.>) = zipWith ($)
_ .> x = x
x <. _ = x
liftF2 = zipWith
-- TODO: Bind
#endif
-------------------------------------------------------------------------------
-- Construction
-------------------------------------------------------------------------------
-- | 'Tree' with exactly one element.
--
-- >>> singleton True
-- Leaf True
--
singleton :: a -> Tree 'Z a
singleton = Leaf
-------------------------------------------------------------------------------
-- Conversions
-------------------------------------------------------------------------------
-- | Convert 'Tree' to list.
--
-- >>> toList $ Node (Node (Leaf 'f') (Leaf 'o')) (Node (Leaf 'o') (Leaf 'd'))
-- "food"
toList :: forall n a. N.SNatI n => Tree n a -> [a]
toList xs = getToList (N.induction1 start step) xs [] where
start :: ToList 'Z a
start = ToList (\(Leaf x) -> (x :))
step :: ToList m a -> ToList ('S m) a
step (ToList f) = ToList $ \(Node x y) -> f x . f y
newtype ToList n a = ToList { getToList :: Tree n a -> [a] -> [a] }
-------------------------------------------------------------------------------
-- Indexing
-------------------------------------------------------------------------------
flipIndex :: N.SNatI n => Wrd n -> Tree n a -> a
flipIndex = getIndex (N.induction1 start step) where
start :: Index 'Z a
start = Index $ \_ (Leaf x) -> x
step :: Index m a-> Index ('N.S m) a
step (Index go) = Index $ \i (Node x y) -> case i of
W0 j -> go j x
W1 j -> go j y
newtype Index n a = Index { getIndex :: Wrd n -> Tree n a -> a }
-- | Indexing.
--
-- >>> let t = Node (Node (Leaf 'a') (Leaf 'b')) (Node (Leaf 'c') (Leaf 'd'))
-- >>> t ! W1 (W0 WE)
-- 'c'
--
(!) :: N.SNatI n => Tree n a -> Wrd n -> a
(!) = flip flipIndex
-- | Tabulating, inverse of '!'.
--
-- >>> tabulate id :: Tree N.Nat2 (Wrd N.Nat2)
-- Node (Node (Leaf 0b00) (Leaf 0b01)) (Node (Leaf 0b10) (Leaf 0b11))
tabulate :: N.SNatI n => (Wrd n -> a) -> Tree n a
tabulate = getTabulate (N.induction1 start step) where
start :: Tabulate 'Z a
start = Tabulate $ \f -> Leaf (f WE)
step :: Tabulate m a -> Tabulate ('S m) a
step (Tabulate go) = Tabulate $ \f -> Node (go (f . W0)) (go (f . W1))
newtype Tabulate n a = Tabulate { getTabulate :: (Wrd n -> a) -> Tree n a }
leftmost :: N.SNatI n => Tree n a -> a
leftmost = getTheMost (N.induction1 start step) where
start :: TheMost 'Z a
start = TheMost $ \(Leaf x) -> x
step :: TheMost m a -> TheMost ('S m) a
step (TheMost go) = TheMost $ \(Node x _) -> go x
rightmost :: N.SNatI n => Tree n a -> a
rightmost = getTheMost (N.induction1 start step) where
start :: TheMost 'Z a
start = TheMost $ \(Leaf x) -> x
step :: TheMost m a -> TheMost ('S m) a
step (TheMost go) = TheMost $ \(Node _ y) -> go y
newtype TheMost n a = TheMost { getTheMost :: Tree n a -> a }
-------------------------------------------------------------------------------
-- Reverse
-------------------------------------------------------------------------------
-- | Reverse 'Tree'.
--
-- >>> let t = Node (Node (Leaf 'a') (Leaf 'b')) (Node (Leaf 'c') (Leaf 'd'))
-- >>> reverse t
-- Node (Node (Leaf 'd') (Leaf 'c')) (Node (Leaf 'b') (Leaf 'a'))
--
reverse :: forall n a. N.SNatI n => Tree n a -> Tree n a
reverse = getReverse (N.induction1 start step) where
start :: Reverse 'Z a
start = Reverse id
step :: N.SNatI m => Reverse m a -> Reverse ('S m) a
step (Reverse go) = Reverse $ \(Node x y) -> Node (go y) (go x)
newtype Reverse n a = Reverse { getReverse :: Tree n a -> Tree n a }
-------------------------------------------------------------------------------
-- Mapping
-------------------------------------------------------------------------------
-- | >>> map not $ Node (Leaf True) (Leaf False)
-- Node (Leaf False) (Leaf True)
--
map :: forall a b n. N.SNatI n => (a -> b) -> Tree n a -> Tree n b
map f = getMap $ N.induction1 start step where
start :: Map a 'Z b
start = Map $ \(Leaf x) -> Leaf (f x)
step :: Map a m b -> Map a ('S m) b
step (Map go) = Map $ \(Node x y) -> Node (go x) (go y)
newtype Map a n b = Map { getMap :: Tree n a -> Tree n b }
-- |
-- >>> let t = Node (Node (Leaf 'a') (Leaf 'b')) (Node (Leaf 'c') (Leaf 'd'))
-- >>> imap (,) t
-- Node (Node (Leaf (0b00,'a')) (Leaf (0b01,'b'))) (Node (Leaf (0b10,'c')) (Leaf (0b11,'d')))
--
imap :: N.SNatI n => (Wrd n -> a -> b) -> Tree n a -> Tree n b
imap = getIMap $ N.induction1 start step where
start :: IMap a 'Z b
start = IMap $ \f (Leaf x) -> Leaf (f WE x)
step :: IMap a m b -> IMap a ('S m) b
step (IMap go) = IMap $ \f (Node x y) ->
Node (go (f . W0) x) (go (f . W1) y)
newtype IMap a n b = IMap { getIMap :: (Wrd n -> a -> b) -> Tree n a -> Tree n b }
-- | Apply an action to every element of a 'Tree', yielding a 'Tree' of results.
traverse :: forall n f a b. (Applicative f, N.SNatI n) => (a -> f b) -> Tree n a -> f (Tree n b)
traverse f = getTraverse $ N.induction1 start step where
start :: Traverse f a 'Z b
start = Traverse $ \(Leaf x) -> Leaf <$> f x
step :: Traverse f a m b -> Traverse f a ('S m) b
step (Traverse go) = Traverse $ \(Node x y) -> liftA2 Node (go x) (go y)
{-# INLINE traverse #-}
newtype Traverse f a n b = Traverse { getTraverse :: Tree n a -> f (Tree n b) }
-- | Apply an action to every element of a 'Tree' and its index, yielding a 'Tree' of results.
itraverse :: forall n f a b. (Applicative f, N.SNatI n) => (Wrd n -> a -> f b) -> Tree n a -> f (Tree n b)
itraverse = getITraverse $ N.induction1 start step where
start :: ITraverse f a 'Z b
start = ITraverse $ \f (Leaf x) -> Leaf <$> f WE x
step :: ITraverse f a m b -> ITraverse f a ('S m) b
step (ITraverse go) = ITraverse $ \f (Node x y) -> liftA2 Node (go (f . W0) x) (go (f . W1) y)
{-# INLINE itraverse #-}
newtype ITraverse f a n b = ITraverse { getITraverse :: (Wrd n -> a -> f b) -> Tree n a -> f (Tree n b) }
#ifdef MIN_VERSION_semigroupoids
-- | Apply an action to non-empty 'Tree', yielding a 'Tree' of results.
traverse1 :: forall n f a b. (Apply f, N.SNatI n) => (a -> f b) -> Tree n a -> f (Tree n b)
traverse1 f = getTraverse $ N.induction1 start step where
start :: Traverse f a 'Z b
start = Traverse $ \(Leaf x) -> Leaf <$> f x
step :: Traverse f a m b -> Traverse f a ('S m) b
step (Traverse go) = Traverse $ \(Node x y) -> liftF2 Node (go x) (go y)
{-# INLINE traverse1 #-}
itraverse1 :: forall n f a b. (Apply f, N.SNatI n) => (Wrd n -> a -> f b) -> Tree n a -> f (Tree n b)
itraverse1 = getITraverse $ N.induction1 start step where
start :: ITraverse f a 'Z b
start = ITraverse $ \f (Leaf x) -> Leaf <$> f WE x
step :: ITraverse f a m b -> ITraverse f a ('S m) b
step (ITraverse go) = ITraverse $ \f (Node x y) -> liftF2 Node (go (f . W0) x) (go (f . W1) y)
{-# INLINE itraverse1 #-}
#endif
-- | Apply an action to every element of a 'Tree' and its index, ignoring the results.
itraverse_ :: forall n f a b. (Applicative f, N.SNatI n) => (Wrd n -> a -> f b) -> Tree n a -> f ()
itraverse_ = getITraverse_ $ N.induction1 start step where
start :: ITraverse_ f a 'Z b
start = ITraverse_ $ \f (Leaf x) -> void (f WE x)
step :: ITraverse_ f a m b -> ITraverse_ f a ('S m) b
step (ITraverse_ go) = ITraverse_ $ \f (Node x y) -> go (f . W0) x *> go (f . W1) y
newtype ITraverse_ f a n b = ITraverse_ { getITraverse_ :: (Wrd n -> a -> f b) -> Tree n a -> f () }
-------------------------------------------------------------------------------
-- Folding
-------------------------------------------------------------------------------
-- | See 'I.Foldable'.
foldMap :: forall a n m. (Monoid m, N.SNatI n) => (a -> m) -> Tree n a -> m
foldMap f = getFold (N.induction1 start step) where
start :: Fold a 'Z m
start = Fold $ \(Leaf x) -> f x
step :: Fold a p m -> Fold a ('S p) m
step (Fold g) = Fold $ \(Node x y) -> g x `mappend` g y
newtype Fold a n b = Fold { getFold :: Tree n a -> b }
-- | See 'I.Foldable1'.
foldMap1 :: forall s a n. (Semigroup s, N.SNatI n) => (a -> s) -> Tree n a -> s
foldMap1 f = getFold $ N.induction1 start step where
start :: Fold a 'Z s
start = Fold $ \(Leaf x) -> f x
step :: Fold a m s -> Fold a ('S m) s
step (Fold g) = Fold $ \(Node x y) -> g x <> g y
-- | See 'I.FoldableWithIndex'.
ifoldMap :: forall a n m. (Monoid m, N.SNatI n) => (Wrd n -> a -> m) -> Tree n a -> m
ifoldMap = getIFoldMap $ N.induction1 start step where
start :: IFoldMap a 'Z m
start = IFoldMap $ \f (Leaf x) -> f WE x
step :: IFoldMap a p m -> IFoldMap a ('S p) m
step (IFoldMap go) = IFoldMap $ \f (Node x y) -> go (f . W0) x `mappend` go (f . W1) y
newtype IFoldMap a n m = IFoldMap { getIFoldMap :: (Wrd n -> a -> m) -> Tree n a -> m }
-- | There is no type-class for this :(
ifoldMap1 :: forall a n s. (Semigroup s, N.SNatI n) => (Wrd ('S n) -> a -> s) -> Tree ('S n) a -> s
ifoldMap1 = getIFoldMap $ N.induction1 start step where
start :: IFoldMap a 'Z m
start = IFoldMap $ \f (Leaf x) -> f WE x
step :: IFoldMap a p s -> IFoldMap a ('S p) s
step (IFoldMap go) = IFoldMap $ \f (Node x y) -> go (f . W0) x <> go (f . W1) y
-- | Right fold.
foldr :: forall a b n. N.SNatI n => (a -> b -> b) -> b -> Tree n a -> b
foldr f = getFoldr (N.induction1 start step) where
start :: Foldr a 'Z b
start = Foldr $ \z (Leaf x) -> f x z
step :: Foldr a m b -> Foldr a ('S m) b
step (Foldr go) = Foldr $ \z (Node x y) -> go (go z y) x
newtype Foldr a n b = Foldr { getFoldr :: b -> Tree n a -> b }
-- | Right fold with an index.
ifoldr :: forall a b n. N.SNatI n => (Wrd n -> a -> b -> b) -> b -> Tree n a -> b
ifoldr = getIFoldr $ N.induction1 start step where
start :: IFoldr a 'Z b
start = IFoldr $ \f z (Leaf x) -> f WE x z
step :: IFoldr a m b -> IFoldr a ('S m) b
step (IFoldr go) = IFoldr $ \f z (Node x y) -> go (f . W0) (go (f . W1) z y) x
newtype IFoldr a n b = IFoldr { getIFoldr :: (Wrd n -> a -> b -> b) -> b -> Tree n a -> b }
foldr1Map :: forall a b n. N.SNatI n => (a -> b -> b) -> (a -> b) -> Tree n a -> b
foldr1Map f = getFoldr1 (N.induction1 start step) where
start :: Foldr1 a 'Z b
start = Foldr1 $ \z (Leaf x) -> z x
step :: Foldr1 a m b -> Foldr1 a ('S m) b
step (Foldr1 go) = Foldr1 $ \z (Node x y) -> go (\z0 -> f z0 (go z y)) x
newtype Foldr1 a n b = Foldr1 { getFoldr1 :: (a -> b) -> Tree n a -> b }
ifoldr1Map :: (Wrd n -> a -> b -> b) -> (Wrd n -> a -> b) -> Tree n a -> b
ifoldr1Map = ifoldr1Map
-- | Left fold.
foldl :: forall a b n. N.SNatI n => (b -> a -> b) -> b -> Tree n a -> b
foldl f = getFoldl (N.induction1 start step) where
start :: Foldl a 'Z b
start = Foldl $ \z (Leaf x) -> f z x
step :: Foldl a m b -> Foldl a ('S m) b
step (Foldl go) = Foldl $ \z (Node x y) -> go (go z x) y
newtype Foldl a n b = Foldl { getFoldl :: b -> Tree n a -> b }
-- | Left fold with an index.
ifoldl :: forall a b n. N.SNatI n => (Wrd n -> b -> a -> b) -> b -> Tree n a -> b
ifoldl = getIFoldl $ N.induction1 start step where
start :: IFoldl a 'Z b
start = IFoldl $ \f z (Leaf x) -> f WE z x
step :: IFoldl a m b -> IFoldl a ('S m) b
step (IFoldl go) = IFoldl $ \f z (Node x y) -> go (f . W0) (go (f . W1) z x) y
newtype IFoldl a n b = IFoldl { getIFoldl :: (Wrd n -> b -> a -> b) -> b -> Tree n a -> b }
-- | Yield the length of a 'Tree'. /O(n)/
length :: forall n a. N.SNatI n => Tree n a -> Int
length _ = getLength l where
l :: Length n
l = N.induction (Length 1) $ \(Length n) -> Length (2 * n)
newtype Length (n :: Nat) = Length { getLength :: Int }
-- | Test whether a 'Tree' is empty. It never is. /O(1)/
null :: Tree n a -> Bool
null _ = False
-------------------------------------------------------------------------------
-- Special folds
-------------------------------------------------------------------------------
-- | Non-strict 'sum'.
sum :: (Num a, N.SNatI n) => Tree n a -> a
sum = getFold $ N.induction1 start step where
start :: Num a => Fold a 'Z a
start = Fold $ \(Leaf x) -> x
step :: Num a => Fold a m a -> Fold a ('S m) a
step (Fold f) = Fold $ \(Node x y) -> f x + f y
-- | Non-strict 'product'.
product :: (Num a, N.SNatI n) => Tree n a -> a
product = getFold $ N.induction1 start step where
start :: Num a => Fold a 'Z a
start = Fold $ \(Leaf x) -> x
step :: Num a => Fold a m a -> Fold a ('S m) a
step (Fold f) = Fold $ \(Node x y) -> f x * f y
-------------------------------------------------------------------------------
-- Zipping
-------------------------------------------------------------------------------
-- | Zip two 'Tree's with a function.
zipWith :: forall a b c n. N.SNatI n => (a -> b -> c) -> Tree n a -> Tree n b -> Tree n c
zipWith f = getZipWith $ N.induction start step where
start :: ZipWith a b c 'Z
start = ZipWith $ \(Leaf x) (Leaf y) -> Leaf (f x y)
step :: ZipWith a b c m -> ZipWith a b c ('S m)
step (ZipWith go) = ZipWith $ \(Node x y) (Node u v) -> Node (go x u) (go y v)
newtype ZipWith a b c n = ZipWith { getZipWith :: Tree n a -> Tree n b -> Tree n c }
-- | Zip two 'Tree's. with a function that also takes the elements' indices.
izipWith :: N.SNatI n => (Wrd n -> a -> b -> c) -> Tree n a -> Tree n b -> Tree n c
izipWith = getIZipWith $ N.induction start step where
start :: IZipWith a b c 'Z
start = IZipWith $ \f (Leaf x) (Leaf y) -> Leaf (f WE x y)
step :: IZipWith a b c m -> IZipWith a b c ('S m)
step (IZipWith go) = IZipWith $ \f (Node x y) (Node u v) -> Node (go (f . W0) x u) (go (f . W1) y v)
newtype IZipWith a b c n = IZipWith { getIZipWith :: (Wrd n -> a -> b -> c) -> Tree n a -> Tree n b -> Tree n c }
-- | Repeat value
--
-- >>> repeat 'x' :: Tree N.Nat2 Char
-- Node (Node (Leaf 'x') (Leaf 'x')) (Node (Leaf 'x') (Leaf 'x'))
--
repeat :: N.SNatI n => x -> Tree n x
repeat x = N.induction1 (Leaf x) $ \t -> Node t t
-------------------------------------------------------------------------------
-- Monadic
-------------------------------------------------------------------------------
-- TODO
-------------------------------------------------------------------------------
-- universe
-------------------------------------------------------------------------------
-- | Get all @'Wrd' n@ in a @'Tree' n@.
--
-- >>> universe :: Tree N.Nat2 (Wrd N.Nat2)
-- Node (Node (Leaf 0b00) (Leaf 0b01)) (Node (Leaf 0b10) (Leaf 0b11))
universe :: N.SNatI n => Tree n (Wrd n)
universe = tabulate id
-------------------------------------------------------------------------------
-- EnsureSpine
-------------------------------------------------------------------------------
-- | Ensure spine.
--
-- If we have an undefined 'Tree',
--
-- >>> let v = error "err" :: Tree N.Nat2 Char
--
-- And insert data into it later:
--
-- >>> let setHead :: a -> Tree N.Nat2 a -> Tree N.Nat2 a; setHead x (Node (Node _ u) v) = Node (Node (Leaf x) u) v
--
-- Then without a spine, it will fail:
--
-- >>> leftmost $ setHead 'x' v
-- *** Exception: err
-- ...
--
-- But with the spine, it won't:
--
-- >>> leftmost $ setHead 'x' $ ensureSpine v
-- 'x'
--
ensureSpine :: N.SNatI n => Tree n a -> Tree n a
ensureSpine = getEnsureSpine (N.induction1 first step) where
first :: EnsureSpine 'Z a
first = EnsureSpine $ \ ~(Leaf x) -> Leaf x
step :: EnsureSpine m a -> EnsureSpine ('S m) a
step (EnsureSpine go) = EnsureSpine $ \ ~(Node x y) -> Node (go x) (go y)
newtype EnsureSpine n a = EnsureSpine { getEnsureSpine :: Tree n a -> Tree n a }
-------------------------------------------------------------------------------
-- QuickCheck
-------------------------------------------------------------------------------
instance N.SNatI n => QC.Arbitrary1 (Tree n) where
liftArbitrary = liftArbitrary
liftShrink = liftShrink
liftArbitrary :: forall n a. N.SNatI n => QC.Gen a -> QC.Gen (Tree n a)
liftArbitrary arb = getArb $ N.induction1 start step where
start :: Arb 'Z a
start = Arb $ Leaf <$> arb
step :: Arb m a -> Arb ('S m) a
step (Arb rec) = Arb $ liftA2 Node rec rec
newtype Arb n a = Arb { getArb :: QC.Gen (Tree n a) }
liftShrink :: forall n a. N.SNatI n => (a -> [a]) -> Tree n a -> [Tree n a]
liftShrink shr = getShr $ N.induction1 start step where
start :: Shr 'Z a
start = Shr $ \(Leaf x) ->Leaf <$> shr x
step :: Shr m a -> Shr ('S m) a
step (Shr rec) = Shr $ \(Node x y) ->
uncurry Node <$> QC.liftShrink2 rec rec (x, y)
newtype Shr n a = Shr { getShr :: Tree n a -> [Tree n a] }
instance (N.SNatI n, QC.Arbitrary a) => QC.Arbitrary (Tree n a) where
arbitrary = QC.arbitrary1
shrink = QC.shrink1
instance (N.SNatI n, QC.CoArbitrary a) => QC.CoArbitrary (Tree n a) where
coarbitrary v = case N.snat :: N.SNat n of
N.SZ -> QC.variant (0 :: Int) . (case v of (Leaf x) -> QC.coarbitrary x)
N.SS -> QC.variant (1 :: Int) . (case v of (Node x y) -> QC.coarbitrary (x, y))
instance (N.SNatI n, QC.Function a) => QC.Function (Tree n a) where
function = case N.snat :: N.SNat n of
N.SZ -> QC.functionMap (\(Leaf x) -> x) Leaf
N.SS -> QC.functionMap (\(Node x y) -> (x, y)) (\(x,y) -> Node x y)