    {-|
        A pseudo derivation.  For each field in the data type, deriving
        @Set@ generates @set@/FieldName/@ v x = x{@/fieldName/@ = v}@.
        This derivation is intended to work around the fact that in Haskell
        assigning to a field is not a first class object (although
        extracting from a field is).
    -}
    module Data.Derive.Set(makeSet) where

    {-

    test :: Computer

    setSpeed :: Int -> Computer -> Computer
    setSpeed v x = x{speed=v}

    setWeight :: Double -> Computer -> Computer
    setWeight v x = x{weight=v}

    test :: Sample

    -}

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

    makeSet :: Derivation
    makeSet = derivationCustom "Set" $ \(_,d) -> Right $ concatMap (makeSetField d) $ dataDeclFields d

    makeSetField :: DataDecl -> String -> [Decl]
    makeSetField d field = [TypeSig sl [name set] typ, bind set [pVar "v",pVar "x"] bod]
        where
            set = "set" ++ title field
            typ = typField `TyFun` (dataDeclType d `TyFun` dataDeclType d)
            typField = fromBangType $ fromJust $ lookup field $ concatMap ctorDeclFields $ dataDeclCtors d

            bod = RecUpdate (var "x") [FieldUpdate (qname field) (var "v")]