    {-|
        A pseudo derivation.  For each field in the data type, deriving
        @Lens@ generates @lens@/FieldName/@ = lens @/fieldName/@
        (\ x v -> v { @/fieldName/@ = x })@.

        This works with the @data-lens@ package.
    -}
    module Data.Derive.Lens(makeLens) where

    {-
    import "data-lens" Data.Lens.Common

    test :: Sample

    test :: Computer

    lensSpeed :: Lens Computer Int
    lensSpeed = lens speed (\x v -> v{speed = x})

    lensWeight :: Lens Computer Double
    lensWeight = lens weight (\x v -> v{weight = x})
    -}

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

    makeLens :: Derivation
    makeLens = derivationCustom "Lens" $ \(_,d) -> Right $ concatMap (makeLensField d) $ dataDeclFields d

    makeLensField :: DataDecl -> String -> [Decl ()]
    makeLensField d field = if isIdent field then [TypeSig () [name ref] typ, bind ref [] bod] else []
        where
            ref = "lens" ++ title field
            typ = tyApps (tyCon "Lens") [dataDeclType d, t]
            Just t = lookup field $ concatMap ctorDeclFields $ dataDeclCtors d

            bod = apps (var "lens")
                [var field
                ,Paren () $ Lambda () [pVar "x",pVar "v"] $ RecUpdate () (var "v") [FieldUpdate () (qname field) (var "x")]]