If I had a record like:
data MaybeTest = MaybeTest {
test0 :: String
test1 :: Maybe Int,
test2 :: Maybe Float,
test3 :: Maybe Int,
test4 :: Maybe String,
test5 :: Maybe String
}
deriving (Typeable, Data, Eq, Show)
is there a simple way to see if all the maybe fields are Nothing? I would like to return Nothing if the records fit this condition else return Just MaybeTest. I want to avoid my current long method of calling each Maybe field and checking if they are Nothing.
Stuff like this usually requires generics. Data.Data generics are generally the easiest to use. You can define a query that checks all Maybe x fields with the isNothing predicate using:
{-# LANGUAGE DeriveDataTypeable #-}
import Data.Maybe (isNothing)
import Data.Data (Data, gmapQ)
import Data.Generics.Aliases (ext1Q)
allNothing :: (Data d) => d -> Bool
allNothing = and . gmapQ (const True `ext1Q` isNothing)
Here, ext1Q constructs a query that applies isNothing to any type matching Maybe b while applying const True to any non-Maybe type. The gmapQ function maps it across all fields of the target type, resulting in a list of booleans that are True for all non-Maybe types and Nothing values but False for all Just x values.
You can test it like so:
data Foo = Foo String (Maybe Int) Char (Maybe Double) deriving (Show, Data)
data Bar = Bar (Maybe [Int]) deriving (Show, Data)
and in GHCi:
λ> allNothing (Foo "x" Nothing 'a' Nothing)
True
λ> allNothing (Foo "x" Nothing 'a' (Just 3.14))
False
λ> allNothing (Bar Nothing)
True
λ> allNothing (Bar (Just [1..10]))
False
With that function available, it's easy to write your desired function:
checkNothing :: (Data d) => d -> Maybe d
checkNothing x | allNothing x = Nothing
| otherwise = Just x
giving:
λ> checkNothing (Foo "x" Nothing 'a' Nothing)
Nothing
λ> checkNothing (Foo "x" Nothing 'a' (Just 3.14))
Just (Foo "x" Nothing 'a' (Just 3.14))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With