{-# LANGUAGE ViewPatterns, PatternGuards #-}
module Hint.Lambda(lambdaHint) where
import Hint.Util
import Hint.Type
import Util
import Data.Maybe
lambdaHint :: DeclHint
lambdaHint _ _ x = concatMap (uncurry lambdaExp) (universeParentBi x) ++ concatMap lambdaDecl (universe x)
lambdaDecl :: Decl_ -> [Idea]
lambdaDecl (toFunBind -> o@(FunBind loc [Match _ name pats (UnGuardedRhs _ bod) bind]))
| isNothing bind, isLambda $ fromParen bod = [err "Redundant lambda" o $ uncurry reform $ fromLambda $ Lambda an pats bod]
| (pats2,bod2) <- etaReduce pats bod, length pats2 < length pats, pvars (drop (length pats2) pats) `disjoint` varss bind
= [err "Eta reduce" (reform pats bod) (reform pats2 bod2)]
where reform p b = FunBind loc [Match an name p (UnGuardedRhs an b) Nothing]
lambdaDecl _ = []
etaReduce :: [Pat_] -> Exp_ -> ([Pat_], Exp_)
etaReduce ps (App _ x (Var _ (UnQual _ (Ident _ y))))
| ps /= [], PVar _ (Ident _ p) <- last ps, p == y, p /= "mr", y `notElem` vars x
= etaReduce (init ps) x
etaReduce ps x = (ps,x)
lambdaExp :: Maybe Exp_ -> Exp_ -> [Idea]
lambdaExp p o@(Paren _ (App _ (Var _ (UnQual _ (Symbol _ x))) y)) | isAtom y, allowLeftSection x =
[warn "Use section" o $ LeftSection an y (toNamed x)]
lambdaExp p o@(Paren _ (App _ (App _ (view -> Var_ "flip") (Var _ x)) y)) | allowRightSection $ fromNamed x =
[warn "Use section" o $ RightSection an (QVarOp an x) y]
lambdaExp p o@Lambda{} | maybe True (not . isInfixApp) p, res <- niceLambda [] o, not $ isLambda res =
[(if isVar res || isCon res then err else warn) "Avoid lambda" o res]
lambdaExp p o@(Lambda _ _ x) | isLambda (fromParen x) && maybe True (not . isLambda) p =
[warn "Collapse lambdas" o $ uncurry (Lambda an) $ fromLambda o]
lambdaExp _ _ = []
fromLambda :: Exp_ -> ([Pat_], Exp_)
fromLambda (Lambda _ ps1 (fromLambda . fromParen -> (ps2,x))) = (transformBi (f $ pvars ps2) ps1 ++ ps2, x)
where f bad x@PVar{} | prettyPrint x `elem` bad = PWildCard an
f bad x = x
fromLambda x = ([], x)