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