--------------------------------------------------------------------- ---Module : Zeros -- a naive and simple data type -- usable to stand in for most kinds of nothing -- added Either and Maybe to import wherever needed -- ---------------------------------------------------------------------- {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE DefaultSignatures #-} {-# LANGUAGE TypeOperators #-} {-# OPTIONS -Wall #-} module Uniform.Zero ( module Uniform.Zero, module Data.Maybe, module Data.Either, -- module GHC.Generics, ) where import Data.Either ( Either (..), either, fromLeft, fromRight, isLeft, isRight, lefts, partitionEithers, rights, ) import Data.Maybe ( Maybe (..), catMaybes, fromJust, fromMaybe, isJust, isNothing, listToMaybe, mapMaybe, maybe, maybeToList, ) import GHC.Generics -- | a minimal algebraic type with nothing than an identity -- useful to identify a specific value in a type class Zeros z where zero :: z default zero :: (Generic z, GZero (Rep z)) => z zero = to gzero isZero, notZero :: Eq z => z -> Bool isZero z = zero == z notZero = not . isZero class GZero a where gzero :: a x instance GZero U1 where gzero = U1 instance Zeros a => GZero (K1 i a) where gzero = K1 zero instance (GZero a, GZero b) => GZero (a :*: b) where gzero = gzero :*: gzero instance GZero a => GZero (M1 i c a) where gzero = M1 gzero instance Zeros Char where zero = ' ' instance Zeros () where zero = () instance Zeros Bool where zero = False -- is this contrary to the Unix tradition? instance Zeros Int where zero = 0 instance Zeros [a] where zero = [] instance (Zeros a, Zeros b) => Zeros (a, b) where zero = (zero, zero) instance (Zeros a, Zeros b, Zeros c) => Zeros (a, b, c) where zero = (zero, zero, zero) instance (Zeros a, Zeros b, Zeros c, Zeros d) => Zeros (a, b, c, d) where zero = (zero, zero, zero, zero) instance (Zeros a, Zeros b, Zeros c, Zeros d, Zeros e) => Zeros (a, b, c, d, e) where zero = (zero, zero, zero, zero, zero) instance Zeros (Maybe a) where zero = Nothing