{-# LANGUAGE DeriveGeneric, DerivingVia #-} import Data.Bifunctor import GHC.Generics import Generic.Functor import System.Exit (exitFailure) -- Testing DeriveFunctor (gfmap) and gsolomap data Empty a deriving Generic deriving Functor via (DeriveFunctor Empty) data Unit a = Unit deriving (Eq, Show, Generic) deriving Functor via (DeriveFunctor Unit) data Result a r = Error a | Ok r deriving (Eq, Show, Generic) deriving Functor via (DeriveFunctor (Result a)) mapError :: (a -> b) -> Result a r -> Result b r mapError = gsolomap mapOk :: (r -> s) -> Result a r -> Result a s mapOk = gsolomap mapBoth :: (a -> b) -> Result a a -> Result b b mapBoth = gsolomap data Writer w a = Writer w a deriving (Eq, Show, Generic) deriving Functor via (DeriveFunctor (Writer w)) mapW :: (w -> w') -> Writer w a -> Writer w' a mapW = gsolomap data Square a b = Square a a b b deriving (Eq, Show, Generic) deriving Functor via (DeriveFunctor (Square a)) mapFirst :: (a -> a') -> Square a b -> Square a' b mapFirst = gsolomap data Twice a = Twice (Either a a) deriving (Eq, Show, Generic) deriving Functor via (DeriveFunctor Twice) -- Testing solomap map1, map1' :: (a -> b) -> Either e (Maybe [(e, a)]) -> Either e (Maybe [(e, b)]) map1 = solomap map1' = fmap . fmap . fmap . fmap -- equivalent definition, just making sure it typechecks map2, map2' :: (a -> b) -> (e -> Either [a] r) -> (e -> Either [b] r) map2 = solomap map2' f = fmap (bimap (fmap f) id) type F a = ([a], Either a ()) map3, map3' :: (a -> b) -> F a -> F b map3 = solomap map3' f = bimap (fmap f) (bimap f id) type G t a = (t, Maybe [Either Bool a]) map4 :: (a -> b) -> G t a -> G t b map4 = solomap map4' = fmap . fmap . fmap . fmap -- Deriving Bifunctor data Tree a b = Node a (Tree a b) (Tree a b) | Leaf b deriving (Eq, Show, Generic) deriving Functor via (DeriveFunctor (Tree a)) deriving Bifunctor via (DeriveBifunctor Tree) data CofreeF f a b = a :< f b deriving (Eq, Show, Generic) deriving Bifunctor via (DeriveBifunctor (CofreeF f)) -- Multimap data Three a b c = One a | Two b | Three c deriving (Eq, Show, Generic) mapThree :: (a -> a') -> (b -> b') -> (c -> c') -> Three a b c -> Three a' b' c' mapThree f g h = gmultimap (f :+ g :+ h :+ ()) type F5 a b c = Either a (b, c) map5 :: (a -> a') -> (b -> b') -> (c -> c') -> F5 a b c -> F5 a' b' c' map5 f g h = multimap (f :+ g :+ h :+ ()) map5' f g h = bimap f (bimap g h) -- Run at least once twice :: Int -> Int twice = (* 2) main :: IO () main = do Unit @= fmap twice Unit Ok 8 @= fmap twice (Ok 4 :: Result () Int) Error 8 @= mapError twice (Error 4 :: Result Int ()) Writer () 8 @= fmap twice (Writer () 4) Writer 8 () @= mapW twice (Writer 4 ()) Square () () 8 10 @= fmap twice (Square () () 4 5) Square 8 10 () () @= mapFirst twice (Square 4 5 () ()) [Twice (Left 8), Twice (Right 10)] @= (fmap . fmap) twice [Twice (Left 4), Twice (Right 5)] Node 8 (Leaf 10) (Leaf 12) @= bimap twice twice (Node 4 (Leaf 5) (Leaf 6)) (8 :< Just 10) @= bimap twice twice (4 :< Just 5) [One 8, Two False, Three 1] @= fmap (mapThree twice not length) [One 4, Two True, Three [()]] let t1 = Right (Just [((), 4)]) map1 twice t1 @= map1' twice t1 let t2 x = Left [x] :: Either [Int] () map2 twice t2 4 @= map2' twice t2 4 let t3 = ([4], Left 5) map3 twice t3 @= map3' twice t3 let t4 = ((), Just [Right 4]) map4 twice t4 @= map4' twice t4 let t5 = [Left 4, Right (False, [()])] fmap (map5 twice not length) t5 @= fmap (map5 twice not length) t5 -- Assert equality (@=) :: (Eq a, Show a) => a -> a -> IO () (@=) x y | x == y = pure () | otherwise = do putStrLn "Not equal:" print x print y exitFailure