Added cabal and vim dir

This commit is contained in:
hellerve
2015-04-05 17:47:08 +02:00
parent 1e73d5652c
commit ae5a30a4a4
2440 changed files with 40465 additions and 0 deletions

View File

@@ -0,0 +1,662 @@
module HLint.Default where
import Control.Arrow
import Control.Exception
import Control.Monad
import Control.Monad.Trans.State
import qualified Data.Foldable
import Data.Foldable(asum, sequenceA_, traverse_, for_)
import Data.Traversable(traverse, for)
import Control.Applicative
import Data.Function
import Data.Int
import Data.Char
import Data.List as Data.List
import Data.List as X
import Data.Maybe
import Data.Monoid
import System.IO
import Control.Concurrent.Chan
import System.Mem.Weak
import Control.Exception.Base
import System.Exit
import Data.Either
import Numeric
import IO as System.IO
import List as Data.List
import Maybe as Data.Maybe
import Monad as Control.Monad
import Char as Data.Char
-- I/O
error = putStrLn (show x) ==> print x
error = mapM_ putChar ==> putStr
error = hGetChar stdin ==> getChar
error = hGetLine stdin ==> getLine
error = hGetContents stdin ==> getContents
error = hPutChar stdout ==> putChar
error = hPutStr stdout ==> putStr
error = hPutStrLn stdout ==> putStrLn
error = hPrint stdout ==> print
error = hWaitForInput a 0 ==> hReady a
error = hPutStrLn a (show b) ==> hPrint a b
error = hIsEOF stdin ==> isEOF
-- EXIT
error = exitWith ExitSuccess ==> exitSuccess
-- ORD
error = not (a == b) ==> a /= b where note = "incorrect if either value is NaN"
error = not (a /= b) ==> a == b where note = "incorrect if either value is NaN"
error = not (a > b) ==> a <= b where note = "incorrect if either value is NaN"
error = not (a >= b) ==> a < b where note = "incorrect if either value is NaN"
error = not (a < b) ==> a >= b where note = "incorrect if either value is NaN"
error = not (a <= b) ==> a > b where note = "incorrect if either value is NaN"
error = compare x y /= GT ==> x <= y
error = compare x y == LT ==> x < y
error = compare x y /= LT ==> x >= y
error = compare x y == GT ==> x > y
--warning = x == a || x == b || x == c ==> x `elem` [a,b,c] where note = ValidInstance "Eq" x
--warning = x /= a && x /= b && x /= c ==> x `notElem` [a,b,c] where note = ValidInstance "Eq" x
--error = compare (f x) (f y) ==> Data.Ord.comparing f x y -- not that great
--error = on compare f ==> Data.Ord.comparing f -- not that great
error = head (sort x) ==> minimum x
error = last (sort x) ==> maximum x
error = head (sortBy f x) ==> minimumBy f x
where _ = isCompare f
error = last (sortBy f x) ==> maximumBy f x
where _ = isCompare f
error "Avoid reverse" = reverse (sort x) ==> sortBy (flip compare) x
error "Avoid reverse" = reverse (sortBy f x) ==> sortBy (flip f) x
where _ = isCompare f
warn = flip (g `on` h) ==> flip g `on` h
warn = (f `on` g) `on` h ==> f `on` (g . h)
-- READ/SHOW
error = showsPrec 0 x "" ==> show x
error = readsPrec 0 ==> reads
error = showsPrec 0 ==> shows
warn = showIntAtBase 16 intToDigit ==> showHex
warn = showIntAtBase 8 intToDigit ==> showOct
-- LIST
error = concat (map f x) ==> concatMap f x
warn = concat [a, b] ==> a ++ b
warn "Use map once" = map f (map g x) ==> map (f . g) x
warn = x !! 0 ==> head x
error = take n (repeat x) ==> replicate n x
where _ = noQuickCheck -- takes too long
error = map f (replicate n x) ==> replicate n (f x)
where _ = noQuickCheck -- takes too long
error = map f (repeat x) ==> repeat (f x)
where _ = noQuickCheck -- takes forever
error = cycle [x] ==> repeat x
where _ = noQuickCheck -- takes forever
error = head (reverse x) ==> last x
error = head (drop n x) ==> x !! n where _ = isNat n
error = reverse (tail (reverse x)) ==> init x where note = IncreasesLaziness
error "Avoid reverse" = reverse (reverse x) ==> x where note = IncreasesLaziness
-- error = take (length x - 1) x ==> init x -- not true for x == []
error = isPrefixOf (reverse x) (reverse y) ==> isSuffixOf x y
error = foldr (++) [] ==> concat
error = foldl (++) [] ==> concat where note = IncreasesLaziness
error = foldl f (head x) (tail x) ==> foldl1 f x
error = foldr f (last x) (init x) ==> foldr1 f x
error = span (not . p) ==> break p
error = break (not . p) ==> span p
error = (takeWhile p x, dropWhile p x) ==> span p x
error = fst (span p x) ==> takeWhile p x
error = snd (span p x) ==> dropWhile p x
error = fst (break p x) ==> takeWhile (not . p) x
error = snd (break p x) ==> dropWhile (not . p) x
error = concatMap (++ "\n") ==> unlines
error = map id ==> id
error = or (map p x) ==> any p x
error = and (map p x) ==> all p x
error = zipWith (,) ==> zip
error = zipWith3 (,,) ==> zip3
warn = length x == 0 ==> null x where note = IncreasesLaziness
warn = x == [] ==> null x
warn "Use null" = length x /= 0 ==> not (null x) where note = IncreasesLaziness
warn "Use :" = (\x -> [x]) ==> (:[])
error = map (uncurry f) (zip x y) ==> zipWith f x y
warn = map f (zip x y) ==> zipWith (curry f) x y where _ = isVar f
error = not (elem x y) ==> notElem x y
warn = foldr f z (map g x) ==> foldr (f . g) z x
error = x ++ concatMap (' ':) y ==> unwords (x:y)
error = intercalate " " ==> unwords
warn = concat (intersperse x y) ==> intercalate x y where _ = notEq x " "
warn = concat (intersperse " " x) ==> unwords x
error "Use any" = null (filter f x) ==> not (any f x)
error "Use any" = filter f x == [] ==> not (any f x)
error = filter f x /= [] ==> any f x
error = any id ==> or
error = all id ==> and
error = any ((==) a) ==> elem a where note = ValidInstance "Eq" a
error = any (== a) ==> elem a
error = any (a ==) ==> elem a where note = ValidInstance "Eq" a
error = all ((/=) a) ==> notElem a where note = ValidInstance "Eq" a
error = all (/= a) ==> notElem a where note = ValidInstance "Eq" a
error = all (a /=) ==> notElem a where note = ValidInstance "Eq" a
error = elem True ==> or
error = notElem False ==> and
error = findIndex ((==) a) ==> elemIndex a
error = findIndex (a ==) ==> elemIndex a
error = findIndex (== a) ==> elemIndex a
error = findIndices ((==) a) ==> elemIndices a
error = findIndices (a ==) ==> elemIndices a
error = findIndices (== a) ==> elemIndices a
error = lookup b (zip l [0..]) ==> elemIndex b l
warn "Length always non-negative" = length x >= 0 ==> True
warn "Use null" = length x > 0 ==> not (null x) where note = IncreasesLaziness
warn "Use null" = length x >= 1 ==> not (null x) where note = IncreasesLaziness
error "Take on a non-positive" = take i x ==> [] where _ = isNegZero i
error "Drop on a non-positive" = drop i x ==> x where _ = isNegZero i
error = last (scanl f z x) ==> foldl f z x
error = head (scanr f z x) ==> foldr f z x
error = iterate id ==> repeat
where _ = noQuickCheck -- takes forever
error = zipWith f (repeat x) ==> map (f x)
error = zipWith f x (repeat y) ==> map (\x -> f x y) x
-- BY
error = deleteBy (==) ==> delete
error = groupBy (==) ==> group
error = insertBy compare ==> insert
error = intersectBy (==) ==> intersect
error = maximumBy compare ==> maximum
error = minimumBy compare ==> minimum
error = nubBy (==) ==> nub
error = sortBy compare ==> sort
error = unionBy (==) ==> union
-- FOLDS
error = foldr (>>) (return ()) ==> sequence_
where _ = noQuickCheck
error = foldr (&&) True ==> and
error = foldl (&&) True ==> and where note = IncreasesLaziness
error = foldr1 (&&) ==> and where note = RemovesError "on []"; _ = noQuickCheck
error = foldl1 (&&) ==> and where note = RemovesError "on []"
error = foldr (||) False ==> or
error = foldl (||) False ==> or where note = IncreasesLaziness
error = foldr1 (||) ==> or where note = RemovesError "on []"
error = foldl1 (||) ==> or where note = RemovesError "on []"
error = foldl (+) 0 ==> sum
error = foldr (+) 0 ==> sum
error = foldl1 (+) ==> sum where note = RemovesError "on []"
error = foldr1 (+) ==> sum where note = RemovesError "on []"
error = foldl (*) 1 ==> product
error = foldr (*) 1 ==> product
error = foldl1 (*) ==> product where note = RemovesError "on []"
error = foldr1 (*) ==> product where note = RemovesError "on []"
error = foldl1 max ==> maximum
error = foldr1 max ==> maximum
error = foldl1 min ==> minimum
error = foldr1 min ==> minimum
error = foldr mplus mzero ==> msum
where _ = noQuickCheck
-- FUNCTION
error = (\x -> x) ==> id
error = (\x y -> x) ==> const
error = (\(x,y) -> y) ==> snd
error = (\(x,y) -> x) ==> fst
warn "Use curry" = (\x y -> f (x,y)) ==> curry f
warn "Use uncurry" = (\(x,y) -> f x y) ==> uncurry f where note = IncreasesLaziness
error "Redundant $" = (($) . f) ==> f
error "Redundant $" = (f $) ==> f
warn = (\x -> y) ==> const y where _ = isAtom y && not (isWildcard y)
error "Redundant flip" = flip f x y ==> f y x where _ = isApp original
warn = (\a b -> g (f a) (f b)) ==> g `Data.Function.on` f
error "Evaluate" = id x ==> x
error "Redundant id" = id . x ==> x
error "Redundant id" = x . id ==> x
-- CHAR
error = a >= 'a' && a <= 'z' ==> isAsciiLower a
error = a >= 'A' && a <= 'Z' ==> isAsciiUpper a
error = a >= '0' && a <= '9' ==> isDigit a
error = a >= '0' && a <= '7' ==> isOctDigit a
error = isLower a || isUpper a ==> isAlpha a
error = isUpper a || isLower a ==> isAlpha a
-- BOOL
error "Redundant ==" = x == True ==> x
warn "Redundant ==" = x == False ==> not x
error "Redundant ==" = True == a ==> a
warn "Redundant ==" = False == a ==> not a
error "Redundant /=" = a /= True ==> not a
warn "Redundant /=" = a /= False ==> a
error "Redundant /=" = True /= a ==> not a
warn "Redundant /=" = False /= a ==> a
error "Redundant if" = (if a then x else x) ==> x where note = IncreasesLaziness
error "Redundant if" = (if a then True else False) ==> a
error "Redundant if" = (if a then False else True) ==> not a
error "Redundant if" = (if a then t else (if b then t else f)) ==> if a || b then t else f
error "Redundant if" = (if a then (if b then t else f) else f) ==> if a && b then t else f
error "Redundant if" = (if x then True else y) ==> x || y where _ = notEq y False
error "Redundant if" = (if x then y else False) ==> x && y where _ = notEq y True
warn "Use if" = case a of {True -> t; False -> f} ==> if a then t else f
warn "Use if" = case a of {False -> f; True -> t} ==> if a then t else f
warn "Use if" = case a of {True -> t; _ -> f} ==> if a then t else f
warn "Use if" = case a of {False -> f; _ -> t} ==> if a then t else f
warn "Redundant if" = (if c then (True, x) else (False, x)) ==> (c, x) where note = IncreasesLaziness
warn "Redundant if" = (if c then (False, x) else (True, x)) ==> (not c, x) where note = IncreasesLaziness
warn = or [x, y] ==> x || y
warn = or [x, y, z] ==> x || y || z
warn = and [x, y] ==> x && y
warn = and [x, y, z] ==> x && y && z
error "Redundant if" = (if x then False else y) ==> not x && y where _ = notEq y True
error "Redundant if" = (if x then y else True) ==> not x || y where _ = notEq y False
error "Redundant not" = not (not x) ==> x
-- error "Too strict if" = (if c then f x else f y) ==> f (if c then x else y) where note = IncreasesLaziness
-- also breaks types, see #87
-- ARROW
error = id *** g ==> second g
error = f *** id ==> first f
error = zip (map f x) (map g x) ==> map (f Control.Arrow.&&& g) x
warn = (\(x,y) -> (f x, g y)) ==> f Control.Arrow.*** g
warn = (\x -> (f x, g x)) ==> f Control.Arrow.&&& g
warn = (\(x,y) -> (f x,y)) ==> Control.Arrow.first f
warn = (\(x,y) -> (x,f y)) ==> Control.Arrow.second f
warn = (f (fst x), g (snd x)) ==> (f Control.Arrow.*** g) x
warn "Redundant pair" = (fst x, snd x) ==> x where note = DecreasesLaziness
-- FUNCTOR
error "Functor law" = fmap f (fmap g x) ==> fmap (f . g) x where _ = noQuickCheck
error "Functor law" = fmap id ==> id where _ = noQuickCheck
warn = fmap f $ x ==> f Control.Applicative.<$> x
where _ = (isApp x || isAtom x) && noQuickCheck
-- MONAD
error "Monad law, left identity" = return a >>= f ==> f a where _ = noQuickCheck
error "Monad law, right identity" = m >>= return ==> m where _ = noQuickCheck
warn = m >>= return . f ==> Control.Monad.liftM f m where _ = noQuickCheck -- cannot be fmap, because is in Functor not Monad
error = (if x then y else return ()) ==> Control.Monad.when x $ _noParen_ y where _ = not (isAtom y) && noQuickCheck
error = (if x then y else return ()) ==> Control.Monad.when x y where _ = isAtom y && noQuickCheck
error = (if x then return () else y) ==> Control.Monad.unless x $ _noParen_ y where _ = not (isAtom y) && noQuickCheck
error = (if x then return () else y) ==> Control.Monad.unless x y where _ = isAtom y && noQuickCheck
error = sequence (map f x) ==> mapM f x where _ = noQuickCheck
error = sequence_ (map f x) ==> mapM_ f x where _ = noQuickCheck
warn = flip mapM ==> Control.Monad.forM where _ = noQuickCheck
warn = flip mapM_ ==> Control.Monad.forM_ where _ = noQuickCheck
warn = flip forM ==> mapM where _ = noQuickCheck
warn = flip forM_ ==> mapM_ where _ = noQuickCheck
error = when (not x) ==> unless x where _ = noQuickCheck
error = x >>= id ==> Control.Monad.join x where _ = noQuickCheck
error = liftM f (liftM g x) ==> liftM (f . g) x where _ = noQuickCheck
error = fmap f (fmap g x) ==> fmap (f . g) x where _ = noQuickCheck
warn = a >> return () ==> Control.Monad.void a
where _ = (isAtom a || isApp a) && noQuickCheck
error = fmap (const ()) ==> Control.Monad.void where _ = noQuickCheck
error = flip (>=>) ==> (<=<) where _ = noQuickCheck
error = flip (<=<) ==> (>=>) where _ = noQuickCheck
error = flip (>>=) ==> (=<<) where _ = noQuickCheck
error = flip (=<<) ==> (>>=) where _ = noQuickCheck
warn = (\x -> f x >>= g) ==> f Control.Monad.>=> g where _ = noQuickCheck
warn = (\x -> f =<< g x) ==> f Control.Monad.<=< g where _ = noQuickCheck
error = a >> forever a ==> forever a where _ = noQuickCheck
warn = liftM2 id ==> ap where _ = noQuickCheck
error = mapM (uncurry f) (zip l m) ==> zipWithM f l m where _ = noQuickCheck
-- STATE MONAD
error = fst (runState x y) ==> evalState x y where _ = noQuickCheck
error = snd (runState x y) ==> execState x y where _ = noQuickCheck
-- MONAD LIST
error = liftM unzip (mapM f x) ==> Control.Monad.mapAndUnzipM f x where _ = noQuickCheck
error = sequence (zipWith f x y) ==> Control.Monad.zipWithM f x y where _ = noQuickCheck
error = sequence_ (zipWith f x y) ==> Control.Monad.zipWithM_ f x y where _ = noQuickCheck
error = sequence (replicate n x) ==> Control.Monad.replicateM n x where _ = noQuickCheck
error = sequence_ (replicate n x) ==> Control.Monad.replicateM_ n x where _ = noQuickCheck
error = mapM f (replicate n x) ==> Control.Monad.replicateM n (f x) where _ = noQuickCheck
error = mapM_ f (replicate n x) ==> Control.Monad.replicateM_ n (f x) where _ = noQuickCheck
error = mapM f (map g x) ==> mapM (f . g) x where _ = noQuickCheck
error = mapM_ f (map g x) ==> mapM_ (f . g) x where _ = noQuickCheck
error = mapM id ==> sequence where _ = noQuickCheck
error = mapM_ id ==> sequence_ where _ = noQuickCheck
-- APPLICATIVE / TRAVERSABLE
error = flip traverse ==> for where _ = noQuickCheck
error = flip for ==> traverse where _ = noQuickCheck
error = flip traverse_ ==> for_ where _ = noQuickCheck
error = flip for_ ==> traverse_ where _ = noQuickCheck
error = foldr (*>) (pure ()) ==> sequenceA_ where _ = noQuickCheck
error = foldr (<|>) empty ==> asum where _ = noQuickCheck
error = liftA2 (flip ($)) ==> (<**>) where _ = noQuickCheck
error = Just <$> a <|> pure Nothing ==> optional a where _ = noQuickCheck
-- LIST COMP
warn "Use list comprehension" = (if b then [x] else []) ==> [x | b]
warn "Redundant list comprehension" = [x | x <- y] ==> y where _ = isVar x
-- SEQ
error "Redundant seq" = x `seq` x ==> x
error "Redundant $!" = id $! x ==> x
error "Redundant seq" = x `seq` y ==> y where _ = isWHNF x
error "Redundant $!" = f $! x ==> f x where _ = isWHNF x
error "Redundant evaluate" = evaluate x ==> return x where _ = isWHNF x
-- MAYBE
error = maybe x id ==> Data.Maybe.fromMaybe x
error = maybe False (const True) ==> Data.Maybe.isJust
error = maybe True (const False) ==> Data.Maybe.isNothing
error = not (isNothing x) ==> isJust x
error = not (isJust x) ==> isNothing x
error = maybe [] (:[]) ==> maybeToList
error = catMaybes (map f x) ==> mapMaybe f x
warn = (case x of Nothing -> y; Just a -> a) ==> fromMaybe y x
error = (if isNothing x then y else f (fromJust x)) ==> maybe y f x
error = (if isJust x then f (fromJust x) else y) ==> maybe y f x
error = maybe Nothing (Just . f) ==> fmap f
warn = map fromJust . filter isJust ==> Data.Maybe.catMaybes
error = x == Nothing ==> isNothing x
error = Nothing == x ==> isNothing x
error = x /= Nothing ==> Data.Maybe.isJust x
error = Nothing /= x ==> Data.Maybe.isJust x
error = concatMap (maybeToList . f) ==> Data.Maybe.mapMaybe f
error = concatMap maybeToList ==> catMaybes
error = maybe n Just x ==> Control.Monad.mplus x n
warn = (case x of Just a -> a; Nothing -> y) ==> fromMaybe y x
error = (if isNothing x then y else fromJust x) ==> fromMaybe y x
error = (if isJust x then fromJust x else y) ==> fromMaybe y x
error = isJust x && (fromJust x == y) ==> x == Just y
error = mapMaybe f (map g x) ==> mapMaybe (f . g) x
error = fromMaybe a (fmap f x) ==> maybe a f x
error = mapMaybe id ==> catMaybes
warn = [x | Just x <- a] ==> Data.Maybe.catMaybes a
warn = (case m of Nothing -> Nothing; Just x -> x) ==> Control.Monad.join m
warn = maybe Nothing id ==> join
warn "Too strict maybe" = maybe (f x) (f . g) ==> f . maybe x g where note = IncreasesLaziness
-- EITHER
error = [a | Left a <- a] ==> lefts a
error = [a | Right a <- a] ==> rights a
error = either Left (Right . f) ==> fmap f
-- INFIX
warn "Use infix" = elem x y ==> x `elem` y where _ = not (isInfixApp original) && not (isParen result)
warn "Use infix" = notElem x y ==> x `notElem` y where _ = not (isInfixApp original) && not (isParen result)
warn "Use infix" = isInfixOf x y ==> x `isInfixOf` y where _ = not (isInfixApp original) && not (isParen result)
warn "Use infix" = isSuffixOf x y ==> x `isSuffixOf` y where _ = not (isInfixApp original) && not (isParen result)
warn "Use infix" = isPrefixOf x y ==> x `isPrefixOf` y where _ = not (isInfixApp original) && not (isParen result)
warn "Use infix" = union x y ==> x `union` y where _ = not (isInfixApp original) && not (isParen result)
warn "Use infix" = intersect x y ==> x `intersect` y where _ = not (isInfixApp original) && not (isParen result)
-- MATHS
error "Redundant fromIntegral" = fromIntegral x ==> x where _ = isLitInt x
error "Redundant fromInteger" = fromInteger x ==> x where _ = isLitInt x
warn = x + negate y ==> x - y
warn = 0 - x ==> negate x
error "Redundant negate" = negate (negate x) ==> x
warn = log y / log x ==> logBase x y
warn = sin x / cos x ==> tan x
warn = n `rem` 2 == 0 ==> even n
warn = n `rem` 2 /= 0 ==> odd n
warn = not (even x) ==> odd x
warn = not (odd x) ==> even x
warn = x ** 0.5 ==> sqrt x
warn "Use 1" = x ^ 0 ==> 1
warn = round (x - 0.5) ==> floor x
-- CONCURRENT
warn = mapM_ (writeChan a) ==> writeList2Chan a
-- EXCEPTION
warn = flip Control.Exception.catch ==> handle
warn = flip handle ==> Control.Exception.catch
warn = flip (catchJust p) ==> handleJust p
warn = flip (handleJust p) ==> catchJust p
warn = Control.Exception.bracket b (const a) (const t) ==> Control.Exception.bracket_ b a t
warn = Control.Exception.bracket (openFile x y) hClose ==> withFile x y
warn = Control.Exception.bracket (openBinaryFile x y) hClose ==> withBinaryFile x y
warn = throw (ErrorCall a) ==> error a
error = toException NonTermination ==> nonTermination
error = toException NestedAtomically ==> nestedAtomically
-- WEAK POINTERS
error = mkWeak a a b ==> mkWeakPtr a b
error = mkWeak a (a, b) c ==> mkWeakPair a b c
-- FOLDABLE
error "Use Foldable.forM_" = (case m of Nothing -> return (); Just x -> f x) ==> Data.Foldable.forM_ m f
where _ = noQuickCheck
error "Use Foldable.forM_" = when (isJust m) (f (fromJust m)) ==> Data.Foldable.forM_ m f
where _ = noQuickCheck
-- EVALUATE
-- TODO: These should be moved in to HSE\Evaluate.hs and applied
-- through a special evaluate hint mechanism
error "Evaluate" = True && x ==> x
error "Evaluate" = False && x ==> False
error "Evaluate" = True || x ==> True
error "Evaluate" = False || x ==> x
error "Evaluate" = not True ==> False
error "Evaluate" = not False ==> True
error "Evaluate" = Nothing >>= k ==> Nothing
error "Evaluate" = either f g (Left x) ==> f x
error "Evaluate" = either f g (Right y) ==> g y
error "Evaluate" = fst (x,y) ==> x
error "Evaluate" = snd (x,y) ==> y
error "Evaluate" = f (fst p) (snd p) ==> uncurry f p
error "Evaluate" = init [x] ==> []
error "Evaluate" = null [] ==> True
error "Evaluate" = length [] ==> 0
error "Evaluate" = foldl f z [] ==> z
error "Evaluate" = foldr f z [] ==> z
error "Evaluate" = foldr1 f [x] ==> x
error "Evaluate" = scanr f z [] ==> [z]
error "Evaluate" = scanr1 f [] ==> []
error "Evaluate" = scanr1 f [x] ==> [x]
error "Evaluate" = take n [] ==> [] where note = IncreasesLaziness
error "Evaluate" = drop n [] ==> [] where note = IncreasesLaziness
error "Evaluate" = takeWhile p [] ==> []
error "Evaluate" = dropWhile p [] ==> []
error "Evaluate" = span p [] ==> ([],[])
error "Evaluate" = lines "" ==> []
error "Evaluate" = unwords [] ==> ""
error "Evaluate" = x - 0 ==> x
error "Evaluate" = x * 1 ==> x
error "Evaluate" = x / 1 ==> x
error "Evaluate" = concat [a] ==> a
error "Evaluate" = concat [] ==> []
error "Evaluate" = zip [] [] ==> []
error "Evaluate" = const x y ==> x
-- COMPLEX
{-
-- these would be a good idea, but we have not yet proven them and they seem to have side conditions
error "Use isPrefixOf" = take (length t) s == t ==> t `Data.List.isPrefixOf` s
error "Use isPrefixOf" = (take i s == t) ==> _eval_ ((i >= length t) && (t `Data.List.isPrefixOf` s))
where _ = (isList t || isLit t) && isPos i
-}
{-
-- clever hint, but not actually a good idea
warn = (do a <- f; g a) ==> f >>= g
where _ = (isAtom f || isApp f)
-}
test = hints named test are to allow people to put test code within hint files
testPrefix = and any prefix also works
{-
<TEST>
yes = concat . map f -- concatMap f
yes = foo . bar . concat . map f . baz . bar -- concatMap f . baz . bar
yes = map f (map g x) -- map (f . g) x
yes = concat.map (\x->if x==e then l' else [x]) -- concatMap (\x->if x==e then l' else [x])
yes = f x where f x = concat . map head -- concatMap head
yes = concat . map f . g -- concatMap f . g
yes = concat $ map f x -- concatMap f x
yes = "test" ++ concatMap (' ':) ["of","this"] -- unwords ("test":["of","this"])
yes = if f a then True else b -- f a || b
yes = not (a == b) -- a /= b
yes = not (a /= b) -- a == b
yes = if a then 1 else if b then 1 else 2 -- if a || b then 1 else 2
no = if a then 1 else if b then 3 else 2
yes = a >>= return . bob -- Control.Monad.liftM bob a
yes = (x !! 0) + (x !! 2) -- head x
yes = if b < 42 then [a] else [] -- [a | b < 42]
no = take n (foo xs) == "hello"
yes = head (reverse xs) -- last xs
yes = reverse xs `isPrefixOf` reverse ys -- isSuffixOf xs ys
no = putStrLn $ show (length xs) ++ "Test"
yes = ftable ++ map (\ (c, x) -> (toUpper c, urlEncode x)) ftable -- toUpper Control.Arrow.*** urlEncode
yes = map (\(a,b) -> a) xs -- fst
yes = map (\(a,_) -> a) xs -- fst
yes = readFile $ args !! 0 -- head args
yes = if Debug `elem` opts then ["--debug"] else [] -- ["--debug" | Debug `elem` opts]
yes = if nullPS s then return False else if headPS s /= '\n' then return False else alter_input tailPS >> return True \
-- if nullPS s || (headPS s /= '\n') then return False else alter_input tailPS >> return True
yes = if foo then do stuff; moreStuff; lastOfTheStuff else return () \
-- Control.Monad.when foo $ do stuff ; moreStuff ; lastOfTheStuff
yes = if foo then stuff else return () -- Control.Monad.when foo stuff
yes = foo $ \(a, b) -> (a, y + b) -- Control.Arrow.second ((+) y)
no = foo $ \(a, b) -> (a, a + b)
yes = map (uncurry (+)) $ zip [1 .. 5] [6 .. 10] -- zipWith (+) [1 .. 5] [6 .. 10]
no = do iter <- textBufferGetTextIter tb ; textBufferSelectRange tb iter iter
no = flip f x $ \y -> y*y+y
no = \x -> f x (g x)
no = foo (\ v -> f v . g)
yes = concat . intersperse " " -- unwords
yes = Prelude.concat $ intersperse " " xs -- unwords xs
yes = concat $ Data.List.intersperse " " xs -- unwords xs
yes = if a then True else False -- a
yes = if x then true else False -- x && true
yes = elem x y -- x `elem` y
yes = foo (elem x y) -- x `elem` y
no = x `elem` y
no = elem 1 [] : []
test a = foo (\x -> True) -- const True
h a = flip f x (y z) -- f (y z) x
h a = flip f x $ y z
yes x = case x of {True -> a ; False -> b} -- if x then a else b
yes x = case x of {False -> a ; _ -> b} -- if x then b else a
no = const . ok . toResponse $ "saved"
yes = case x z of Nothing -> y z; Just pattern -> pattern -- fromMaybe (y z) (x z)
yes = if p then s else return () -- Control.Monad.when p s
error = a $$$$ b $$$$ c ==> a . b $$$$$ c
yes = when (not . null $ asdf) -- unless (null asdf)
yes = id 1 -- 1
yes = case concat (map f x) of [] -> [] -- concatMap f x
yes = [v | v <- xs] -- xs
no = [Left x | Left x <- xs]
when p s = if p then s else return ()
no = x ^^ 18.5
instance Arrow (->) where first f = f *** id
yes = fromInteger 12 -- 12
import Prelude hiding (catch); no = catch
import Control.Exception as E; no = E.catch
main = do f; putStrLn $ show x -- print x
main = map (writer,) $ map arcObj $ filter (rdfPredEq (Res dctreferences)) ts -- map ((writer,) . arcObj) (filter (rdfPredEq (Res dctreferences)) ts)
h x y = return $! (x, y) -- return (x, y)
h x y = return $! x
getInt = do { x <- readIO "0"; return $! (x :: Int) }
foo = evaluate [12] -- return [12]
test = \ a -> f a >>= \ b -> return (a, b)
fooer input = catMaybes . map Just $ input -- mapMaybe Just
yes = mapMaybe id -- catMaybes
main = print $ map (\_->5) [2,3,5] -- const 5
main = head $ drop n x
main = head $ drop (-3) x -- x
main = head $ drop 2 x -- x !! 2
main = drop 0 x -- x
main = take 0 x -- []
main = take (-5) x -- []
main = take (-y) x
main = take 4 x
main = let (first, rest) = (takeWhile p l, dropWhile p l) in rest -- span p l
main = map $ \ d -> ([| $d |], [| $d |])
pairs (x:xs) = map (\y -> (x,y)) xs ++ pairs xs
{-# ANN foo "HLint: ignore" #-};foo = map f (map g x) -- @Ignore ???
yes = fmap lines $ abc 123 -- lines Control.Applicative.<$> abc 123
no = fmap lines $ abc $ def 123
test = foo . not . not -- id
test = map (not . not) xs -- id
used = not . not . any (`notElem` special) . fst . derives -- any (`notElem` special) . fst . derives
test = foo . id . map -- map
test = food id xs
yes = baz baz >> return () -- Control.Monad.void (baz baz)
no = foo >>= bar >>= something >>= elsee >> return ()
no = f (#) x
data Pair = P {a :: !Int}; foo = return $! P{a=undefined}
data Pair = P {a :: !Int}; foo = return $! P undefined
foo = return $! Just undefined -- return (Just undefined)
foo = return $! (a,b) -- return (a,b)
foo = return $! 1
foo = return $! "test"
bar = [x| (x,_) <- pts]
return' x = x `seq` return x
foo = last (sortBy (compare `on` fst) xs) -- maximumBy (compare `on` fst) xs
g = \ f -> parseFile f >>= (\ cu -> return (f, cu))
foo = bar $ \(x,y) -> x x y
foo = (\x -> f x >>= g) -- f Control.Monad.>=> g
foo = (\f -> h f >>= g) -- h Control.Monad.>=> g
foo = (\f -> h f >>= f)
foo = bar $ \x -> [x,y]
foo = bar $ \x -> [z,y] -- const [z,y]
f condition tChar tBool = if condition then _monoField tChar else _monoField tBool
foo = maybe Bar{..} id -- Data.Maybe.fromMaybe Bar{..}
foo = (\a -> Foo {..}) 1
import Prelude \
yes = flip mapM -- Control.Monad.forM
import Control.Monad \
yes = flip mapM -- forM
import Control.Monad(forM) \
yes = flip mapM -- forM
import Control.Monad(forM_) \
yes = flip mapM -- Control.Monad.forM
import qualified Control.Monad \
yes = flip mapM -- Control.Monad.forM
import qualified Control.Monad as CM \
yes = flip mapM -- CM.forM
import qualified Control.Monad as CM(forM,filterM) \
yes = flip mapM -- CM.forM
import Control.Monad as CM(forM,filterM) \
yes = flip mapM -- forM
import Control.Monad hiding (forM) \
yes = flip mapM -- Control.Monad.forM
import Control.Monad hiding (filterM) \
yes = flip mapM -- forM
import qualified Data.Text.Lazy as DTL \
main = DTL.concat $ map (`DTL.snoc` '-') [DTL.pack "one", DTL.pack "two", DTL.pack "three"]
import Text.Blaze.Html5.Attributes as A \
main = A.id (stringValue id')
</TEST>
-}

View File

@@ -0,0 +1,11 @@
module HLint.Dollar where
error = a $ b $ c ==> a . b $ c
{-
<TEST>
yes = concat $ concat $ map f x -- concat . concat $ map f x
</TEST>
-}

View File

@@ -0,0 +1,11 @@
module HLint.Generalise where
import Data.Monoid
import Control.Monad
warn = concatMap ==> (=<<)
warn = liftM ==> fmap
where _ = noQuickCheck
warn = map ==> fmap
warn = a ++ b ==> a `Data.Monoid.mappend` b

View File

@@ -0,0 +1,5 @@
module HLint.HLint where
import "hint" HLint.Default
import "hint" HLint.Builtin.All

View File

@@ -0,0 +1,130 @@
{-# LANGUAGE NoMonomorphismRestriction, ExtendedDefaultRules, ScopedTypeVariables, DeriveDataTypeable, ViewPatterns #-}
{-# LANGUAGE FlexibleInstances, UndecidableInstances, OverlappingInstances, GeneralizedNewtypeDeriving #-}
{-# LANGUAGE StandaloneDeriving #-}
-- | Used with --quickcheck
module HLint_QuickCheck(module HLint_QuickCheck, module X) where
import System.IO.Unsafe
import Data.Typeable
import Data.List
import Data.Maybe
import Data.IORef
import Control.Exception
import Control.Monad
import System.IO
import Control.Concurrent.Chan
import System.Mem.Weak(Weak)
import Test.QuickCheck hiding ((==>))
import Test.QuickCheck.Test hiding (test)
import Test.QuickCheck.Modifiers as X
default(Maybe Bool,[Bool],Int,Dbl)
-- We need a Show instance that nails down the sides, so defaulting works.
-- The one from Text.Show.Functions is insufficient.
instance (Show a, Show b) => Show (a -> b) where show _ = "<func>"
newtype Dbl = Dbl Double deriving (Enum,Floating,Fractional,Num,Read,Real,RealFloat,RealFrac,Show,Typeable,Arbitrary,CoArbitrary)
instance Eq Dbl where
Dbl a == Dbl b | isNaN a && isNaN b = True
| otherwise = abs (a - b) < 1e-4 || let s = a+b in s /= 0 && abs ((a-b)/s) < 1e-8
instance Ord Dbl where
compare a b | a == b = EQ
compare (Dbl a) (Dbl b) = compare a b
newtype NegZero a = NegZero a deriving (Typeable, Show)
instance (Num a, Arbitrary a) => Arbitrary (NegZero a) where
arbitrary = fmap (NegZero . negate . abs) arbitrary
newtype Nat a = Nat a deriving (Typeable, Show)
instance (Num a, Arbitrary a) => Arbitrary (Nat a) where
arbitrary = fmap (Nat . abs) arbitrary
newtype Compare a = Compare (a -> a -> Ordering) deriving (Typeable, Show)
instance (Ord a, Arbitrary a) => Arbitrary (Compare a) where
arbitrary = fmap (\b -> Compare $ (if b then flip else id) compare) arbitrary
instance Show a => Show (IO a) where show _ = "<IO>"
instance Show a => Show (Weak a) where show _ = "<Weak>"
instance Show a => Show (Chan a) where show _ = "<Chan>"
instance Eq (IO a) where _ == _ = True
instance Eq SomeException where a == b = show a == show b
deriving instance Typeable IOMode
instance Arbitrary Handle where arbitrary = elements [stdin, stdout, stderr]
instance CoArbitrary Handle where coarbitrary _ = variant 0
instance Arbitrary IOMode where arbitrary = elements [ReadMode,WriteMode,AppendMode,ReadWriteMode]
instance Arbitrary a => Arbitrary (IO a) where arbitrary = fmap return arbitrary
instance Arbitrary (Chan a) where arbitrary = return $ unsafePerformIO newChan
instance Exception (Maybe Bool)
data Test a = Test Bool a a deriving (Show, Typeable)
instance Functor Test where
fmap f (Test a b c) = Test a (f b) (f c)
a ==> b = Test False a b
a ?==> b = Test True a b
class Testable2 a where
property2 :: Test a -> Property
instance Testable2 a => Testable (Test a) where
property = property2
instance Eq a => Testable2 a where
property2 (Test bx (catcher -> x) (catcher -> y)) =
property $ (bx && isNothing x) || x == y
instance (Arbitrary a, Show a, Testable2 b) => Testable2 (a -> b) where
property2 x = property $ \a -> fmap ($ a) x
{-# NOINLINE bad #-}
bad :: IORef Int
bad = unsafePerformIO $ newIORef 0
test :: (Show p, Testable p, Typeable p) => FilePath -> Int -> String -> p -> IO ()
test file line hint p = do
res <- quickCheckWithResult stdArgs{chatty=False} p
unless (isSuccess res) $ do
putStrLn $ "\n" ++ file ++ ":" ++ show line ++ ": " ++ hint
print $ typeOf p
putStr $ output res
modifyIORef bad (+1)
catcher :: a -> Maybe a
catcher x = unsafePerformIO $ do
res <- try $ evaluate x
return $ case res of
Left (_ :: SomeException) -> Nothing
Right v -> Just v
_noParen_ = id
_eval_ = id
withMain :: IO () -> IO ()
withMain act = do
act
bad <- readIORef bad
when (bad > 0) $
error $ "Failed " ++ show bad ++ " tests"
---------------------------------------------------------------------
-- EXAMPLES
main :: IO ()
main = withMain $ do
let t = \ a -> (findIndex ((==) a)) ==> (elemIndex a)
in test "data\\Default.hs" 144 "findIndex ((==) a) ==> elemIndex a" t
let t = ((foldr1 (&&)) ?==> (and))
in test "data\\Default.hs" 179 "foldr1 (&&) ==> and" t
let t = \ x -> (sqrt x) ==> (x ** 0.5)
in test "data\\Default.hs" 407 "sinh x / cosh x ==> tanh x" t
let t = \ (NegZero i) x -> (take i x) ==> ([])
in test "data\\Default.hs" 154 "take i x ==> []" t
let t = \ (Compare f) x -> (head (sortBy f x)) ==> (minimumBy f x)
in test "data\\Default.hs" 70 "head (sortBy f x) ==> minimumBy f x" t
let t = \ f -> ((f $)) ==> (f)
in test "data\\Default.hs" 218 "(f $) ==> f" t

View File

@@ -0,0 +1,19 @@
-- Used with --typecheck
module HLint_TypeCheck where
(==>) :: a -> a -> a
(==>) = undefined
_noParen_ = id
_eval_ = id
---------------------------------------------------------------------
-- EXAMPLES
main :: IO ()
main = return ()
{-# LINE 116 "data\\Default.hs" #-}
_test64 = \ p x -> (and (map p x)) ==> (all p x)

View File

@@ -0,0 +1,115 @@
-- These hints are for test purposes, and are not intended to
-- be used for real.
-- FIXME: Should make this module modules in one file, so can easily test lots of
-- things without them overlapping
module HLint.Test where
import "hint" HLint.Builtin.All
error = Prelude.readFile ==> bad
error = (x :: Int) ==> (x :: Int32)
where _ = noTypeCheck
error "Test1" = scanr ==> scanr
error "Test2" = filter ==> filter
error "Test3" = foldr ==> foldr
error "Test4" = foldl ==> foldl
ignore "Test1" = ""
ignore "Test3"
ignore "Test2" = ignoreTest
warn = ignoreTest3
ignore = Ignore_Test
{-# ANN module "HLint: ignore Test4" #-}
{-# ANN annTest2 "HLint: error" #-}
{-# ANN annTest3 ("HLint: warn" :: String) #-}
{-# ANN type Ann_Test ("HLint: ignore") #-}
error = concat (map f x) ==> Data.List.concatMap f x
infix 9 +
error = a * (b+c) ==> undefined
error = Array.head ==> head
error = tail ==> Array.tail
warn = id Control.Arrow.*** id ==> id
error = zip [1..length x] x ==> zipFrom 1 x
error = before a ==> after a
{-
<TEST>
main = readFile "foo" >>= putStr \
-- bad
import Prelude hiding(readFile) \
import Data.ByteString.Char8(readFile) \
test = readFile "foo" >>= putStr
import Prelude as Prelude2 \
yes = Prelude2.readFile "foo" >>= putStr \
-- bad
yes = 32 :: Int -- 32 :: Int32
yes = before 12 -- after 12
ignoreTest = filter -- @Ignore ???
ignoreTest2 = filter -- @Error ???
ignoreTest3 = filter -- @Warning ???
ignoreAny = scanr -- @Ignore ???
ignoreNew = foldr -- @Ignore ???
type Ignore_Test = Int -- @Ignore ???
annTest = foldl -- @Ignore ???
annTest2 = foldl -- @Error ???
annTest3 = scanr -- @Warning ???
type Ann_Test = Int -- @Ignore ???
concatMap f x = concat (map f x)
concatMop f x = concat (map f x) -- Data.List.concatMap f x
yes = 1 * 2+3 -- undefined
import Foo; test = Foo.id 1
test = head
import Array; test = Array.head -- head
test = Array.head -- head
test = head
import qualified Array; test = head
import Array(tail); test = head
import Array(head); test = head -- head
import Array as A; test = A.head -- head
test = tail -- Array.tail
import qualified Array as B; test = tail -- B.tail
import Control.Arrow; test = id *** id -- id
test = id Control.Arrow.*** id -- id
import Control.Arrow as Q; test = id Q.*** id -- id
zip [1..length x]
zip [1..length x] x -- zipFrom 1 x
{-# ANN module "HLint: ignore Unused LANGUAGE pragma" #-} \
{-# LANGUAGE RecordWildCards #-} -- @Ignore ???
{-# ANN module "HLint: ignore Unused LANGUAGE pragma" #-} \
{-# LANGUAGE RecordWildCards #-} -- @Ignore ???
{-# ANN module "HLint: ignore Use import/export shortcut" #-} \
module ABCD(module A, module B, module C) where \
import A; import B; import C -- @Ignore ???
{-# ANN lam "HLint: ignore Redundant lambda" #-} \
lam = \x -> x x x -- @Ignore ???
{-# ANN module "HLint: ignore Reduce duplication" #-} \
dup = do a; a; a; a; a; a -- @Ignore ???
</TEST>
-}

View File

@@ -0,0 +1,47 @@
.TH HLINT "1" "July 2009" "HLint (C) Neil Mitchell 2006-2009" "User Commands"
.SH NAME
HLint \- haskell source code suggestions
.SH SYNOPSIS
.B hlint
[\fIfiles/directories\fR] [\fIoptions\fR]
.SH DESCRIPTION
\fIHLint\fR is a tool for suggesting possible improvements to Haskell code. These suggestions include ideas such as using alternative functions, simplifying code and spotting redundancies.
.SH OPTIONS
.TP
\fB\-?\fR \fB\-\-help\fR
Display help message
.TP
\fB\-v\fR \fB\-\-version\fR
Display version information
.TP
\fB\-r[file]\fR \fB\-\-report\fR[=\fIfile\fR]
Generate a report in HTML
.TP
\fB\-h\fR \fIfile\fR \fB\-\-hint\fR=\fIfile\fR
Hint/ignore file to use
.TP
\fB\-c\fR \fB\-\-color\fR, \fB\-\-colour\fR
Color the output (requires ANSI terminal)
.TP
\fB\-i\fR \fImessage\fR \fB\-\-ignore\fR=\fImessage\fR
Ignore a particular hint
.TP
\fB\-s\fR \fB\-\-show\fR
Show all ignored ideas
.TP
\fB\-t\fR \fB\-\-test\fR
Run in test mode
.SH EXAMPLE
"To check all Haskell files in 'src' and generate a report type:"
.IP
hlint src \fB\-\-report\fR
.SH "SEE ALSO"
The full documentation for
.B HLint
is available in \fI/usr/share/doc/hlint/hlint.html\fI.
.SH AUTHOR
This manual page was written by Joachim Breitner <nomeata@debian.org>
for the Debian system (but may be used by others).

View File

@@ -0,0 +1,32 @@
-- -*- mode: haskell; -*-
-- Begin copied material.
-- <http://www.cs.kent.ac.uk/people/staff/cr3/toolbox/haskell/dot-squashed.ghci641>
:{
:def redir \varcmd -> return $
case break Data.Char.isSpace varcmd of
(var,_:cmd) -> unlines
[":set -fno-print-bind-result"
,"tmp <- System.Directory.getTemporaryDirectory"
,"(f,h) <- System.IO.openTempFile tmp \"ghci\""
,"sto <- GHC.Handle.hDuplicate System.IO.stdout"
,"GHC.Handle.hDuplicateTo h System.IO.stdout"
,"System.IO.hClose h"
,cmd
,"GHC.Handle.hDuplicateTo sto System.IO.stdout"
,"let readFileNow f = readFile f >>= \\t->Data.List.length t `seq` return t"
,var++" <- readFileNow f"
,"System.Directory.removeFile f"
]
_ -> "putStrLn \"usage: :redir <var> <cmd>\""
:}
--- Integration with the hlint code style tool
:{
:def hlint \extra -> return $ unlines
[":unset +t +s"
,":set -w"
,":redir hlintvar1 :show modules"
,":cmd return $ \":! hlint \" ++ unwords (map (takeWhile (/=',') . drop 2 . dropWhile (/= '(')) $ lines hlintvar1) ++ \" \" ++ " ++ show extra
,":set +t +s -Wall"
]
:}

View File

@@ -0,0 +1,126 @@
;;; hs-lint.el --- minor mode for HLint code checking
;; Copyright 2009 (C) Alex Ott
;;
;; Author: Alex Ott <alexott@gmail.com>
;; Keywords: haskell, lint, HLint
;; Requirements:
;; Status: distributed under terms of GPL2 or above
;; Typical message from HLint looks like:
;;
;; /Users/ott/projects/lang-exp/haskell/test.hs:52:1: Eta reduce
;; Found:
;; count1 p l = length (filter p l)
;; Why not:
;; count1 p = length . filter p
(require 'compile)
(defgroup hs-lint nil
"Run HLint as inferior of Emacs, parse error messages."
:group 'tools
:group 'haskell)
(defcustom hs-lint-command "hlint"
"The default hs-lint command for \\[hlint]."
:type 'string
:group 'hs-lint)
(defcustom hs-lint-save-files t
"Save modified files when run HLint or no (ask user)"
:type 'boolean
:group 'hs-lint)
(defcustom hs-lint-replace-with-suggestions nil
"Replace user's code with suggested replacements"
:type 'boolean
:group 'hs-lint)
(defcustom hs-lint-replace-without-ask nil
"Replace user's code with suggested replacements automatically"
:type 'boolean
:group 'hs-lint)
(defun hs-lint-process-setup ()
"Setup compilation variables and buffer for `hlint'."
(run-hooks 'hs-lint-setup-hook))
;; regex for replace suggestions
;;
;; ^\(.*?\):\([0-9]+\):\([0-9]+\): .*
;; Found:
;; \s +\(.*\)
;; Why not:
;; \s +\(.*\)
(defvar hs-lint-regex
"^\\(.*?\\):\\([0-9]+\\):\\([0-9]+\\): .*[\n\C-m]Found:[\n\C-m]\\s +\\(.*\\)[\n\C-m]Why not:[\n\C-m]\\s +\\(.*\\)[\n\C-m]"
"Regex for HLint messages")
(defun make-short-string (str maxlen)
(if (< (length str) maxlen)
str
(concat (substring str 0 (- maxlen 3)) "...")))
(defun hs-lint-replace-suggestions ()
"Perform actual replacement of suggestions"
(goto-char (point-min))
(while (re-search-forward hs-lint-regex nil t)
(let* ((fname (match-string 1))
(fline (string-to-number (match-string 2)))
(old-code (match-string 4))
(new-code (match-string 5))
(msg (concat "Replace '" (make-short-string old-code 30)
"' with '" (make-short-string new-code 30) "'"))
(bline 0)
(eline 0)
(spos 0)
(new-old-code ""))
(save-excursion
(switch-to-buffer (get-file-buffer fname))
(goto-line fline)
(beginning-of-line)
(setf bline (point))
(when (or hs-lint-replace-without-ask
(yes-or-no-p msg))
(end-of-line)
(setf eline (point))
(beginning-of-line)
(setf old-code (regexp-quote old-code))
(while (string-match "\\\\ " old-code spos)
(setf new-old-code (concat new-old-code
(substring old-code spos (match-beginning 0))
"\\ *"))
(setf spos (match-end 0)))
(setf new-old-code (concat new-old-code (substring old-code spos)))
(remove-text-properties bline eline '(composition nil))
(when (re-search-forward new-old-code eline t)
(replace-match new-code nil t)))))))
(defun hs-lint-finish-hook (buf msg)
"Function, that is executed at the end of HLint execution"
(if hs-lint-replace-with-suggestions
(hs-lint-replace-suggestions)
(next-error 1 t)))
(define-compilation-mode hs-lint-mode "HLint"
"Mode for check Haskell source code."
(set (make-local-variable 'compilation-process-setup-function)
'hs-lint-process-setup)
(set (make-local-variable 'compilation-disable-input) t)
(set (make-local-variable 'compilation-scroll-output) nil)
(set (make-local-variable 'compilation-finish-functions)
(list 'hs-lint-finish-hook))
)
(defun hs-lint ()
"Run HLint for current buffer with haskell source"
(interactive)
(save-some-buffers hs-lint-save-files)
(compilation-start (concat hs-lint-command " \"" buffer-file-name "\"")
'hs-lint-mode))
(provide 'hs-lint)
;;; hs-lint.el ends here

View File

@@ -0,0 +1,169 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
<title>HLint Report</title>
<script type='text/javascript'>
/* == Algorithm for show/unshow ==
Each hint/file is given a number, hint# or file#
When we say showOnly with a class name we add the rules to
the css #content div {display:none}, #content div.className {display:block}
When going back to showAll we remove these results
*/
// CSS MANIPULATION //
function deleteRules(n)
{
var css = document.styleSheets[0];
for (var i = 0; i < n; i++)
css.deleteRule(css.cssRules.length-1);
}
function insertRule(s)
{
var css = document.styleSheets[0];
css.insertRule(s, css.cssRules.length);
}
// SHOW/HIDE LOGIC //
var last = "";
function show(id)
{
if (id == last) return;
if (id == "")
{
deleteRules(3);
insertRule(".all {font-weight: bold;}");
}
else
{
if (last == "")
{
deleteRules(1);
insertRule("#content div {display:none;}");
}
else
{
deleteRules(2);
}
insertRule("#content div." + id + " {display:block;}");
insertRule("#" + id + "{font-weight:bold;}");
}
last = id;
}
</script>
<style type="text/css">
/* These rules are manipulated by the script.
The commented form is how it looks with an id selected */
.all {font-weight: bold;} /* #content div {display:none;} */
/* #content div.id {display:block;} */
/* #id {font-weight: bold;} */
</style>
<style type="text/css">
/* See http://www.webreference.com/programming/css_frames/ */
body {
margin:0;
border:0;
padding:0;
height:100%;
max-height:100%;
font-family: sans-serif;
font-size:76%;
overflow: hidden;
}
#leftbar {
position:absolute;
top:0px;
left:0px;
width: 215px;
bottom: 0px;
overflow:auto;
background:rgb(202,223,255);
margin: 10px;
padding-top: 0;
padding-left: 7px;
padding-right: 7px;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
display:none; /* Override if script present */
}
#content {
position:absolute;
top:0;
bottom:0;
right:0;
overflow:auto;
padding-bottom: 15px;
padding-right: 7px;
left:10px; /* Override if script present */
}
#leftbar ul {margin-top: 0px; padding-left: 15px;}
#leftbar p {margin-bottom: 0px;}
.note {color: gray; font-size: smaller;}
pre {
font-family: "lucida console", monospace;
padding-left: 15px;
margin: 2px;
}
#content div {
margin-bottom: 10px;
margin-right: 10px;
padding-top: 4px;
border-top: 1px solid #ccc;
}
.script #content {left:250px;}
.script #leftbar {display: block;}
/* From HsColour */
.hs-keyglyph, .hs-layout {color: red;}
.hs-keyword {color: blue;}
.hs-comment, .hs-comment a {color: green;}
.hs-str, .hs-chr {color: teal;}
</style>
</head>
<body>
<script type='text/javascript'>
document.body.className = "script";
</script>
<div id="leftbar" valign="top" style="min-width:200px">
<p><a class="all" href="javascript:show('')">All hints</a></p>
<ul>
$HINTS
</ul>
<p><a class="all" href="javascript:show('')">All files</a></p>
<ul>
$FILES
</ul>
</div>
<div id="content" valign="top" width="100%">
<p>
Report generated by <a href="http://community.haskell.org/~ndm/hlint/">HLint</a>
$VERSION
- a tool to suggest improvements to your Haskell code.
</p>
$CONTENT
</div>
</body>
</html>