    {-|
        Has is a pseudo derivation.  For each field of any constructor of
        the data type, Has generates @has@/FieldName/ which returns 'True'
        if given the the given field is a member of the constructor of the
        passed object, and 'False' otherwise.
    -}
    module Data.Derive.Has(makeHas) where

    {-
    test :: Computer

    hasSpeed :: Computer -> Bool
    hasSpeed _ = True

    hasWeight :: Computer -> Bool
    hasWeight Laptop{} = True
    hasWeight _ = False

    test :: Sample
    -}

    import Language.Haskell
    import Data.Derive.Internal.Derivation
    import Data.List

    makeHas :: Derivation
    makeHas = derivationCustom "Has" $ \(_,d) -> Right $ concatMap (makeHasField d) $ dataDeclFields d

    makeHasField :: DataDecl -> String -> [Decl]
    makeHasField d field = [TypeSig sl [name has] typ, binds has ms]
        where
            has = "has" ++ title field
            typ = TyFun (dataDeclType d) (tyCon "Bool")
            (yes,no) = partition (elem field . map fst . ctorDeclFields) $ dataDeclCtors d
            match pat val = ([pat], con val)

            ms | null no = [match PWildCard "True"]
               | otherwise = [match (PRec (qname $ ctorDeclName c) []) "True" | c <- yes] ++ [match PWildCard "False"]