packages feed

generic-functor-0.0.1.0: test/test.hs

{-# 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

-- 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)]

  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

-- Assert equality
(@=) :: (Eq a, Show a) => a -> a -> IO ()
(@=) x y | x == y = pure ()
         | otherwise = do
  putStrLn "Not equal:"
  print x
  print y
  exitFailure