hlint-1.8.53/ 0000755 0000000 0000000 00000000000 12220306165 011111 5 ustar 00 0000000 0000000 hlint-1.8.53/Setup.hs 0000644 0000000 0000000 00000000056 12220306165 012546 0 ustar 00 0000000 0000000 import Distribution.Simple
main = defaultMain
hlint-1.8.53/LICENSE 0000644 0000000 0000000 00000002764 12220306165 012127 0 ustar 00 0000000 0000000 Copyright Neil Mitchell 2006-2012.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of Neil Mitchell nor the names of other
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
hlint-1.8.53/hlint.htm 0000644 0000000 0000000 00000045520 12220306165 012747 0 ustar 00 0000000 0000000
HLint Manual
HLint Manual
by Neil Mitchell
HLint is a tool for suggesting possible improvements to Haskell code. These suggestions include ideas such as using alternative functions, simplifying code and spotting redundancies. This document is structured as follows:
- Installing and running HLint
- FAQ
- Customizing the hints
Acknowledgements
This program has only been made possible by the presence of the haskell-src-exts package, and many improvements have been made by Niklas Broberg in response to feature requests. Additionally, many people have provided help and patches, including Lennart Augustsson, Malcolm Wallace, Henk-Jan van Tuyl, Gwern Branwen, Alex Ott, Andy Stewart, Roman Leshchinskiy and others.
Bugs and limitations
To report a bug either email me, or add the issue directly to the bug tracker. There are three common issues that I do not intend to fix:
- The presence of seq may cause some hints (i.e. eta-reduction) to change the semantics of a program.
- Either the monomorphism restriction, or rank-2 types, may cause transformed programs to require type signatures to be manually inserted.
- HLint operates on each module at a time in isolation, as a result HLint does not know about types or which names are in scope.
Installing and running HLint
Installation follows the standard pattern of any Haskell library or program, type cabal update to update your local hackage database, then cabal install hlint to install HLint.
Once HLint is installed, run hlint source where source is either a Haskell file, or a directory containing Haskell files. A directory will be searched recursively for any files ending with .hs or .lhs. For example, running HLint over darcs would give:
$ hlint darcs-2.1.2
darcs-2.1.2\src\CommandLine.lhs:94:1: Error: Use concatMap
Found:
concat $ map escapeC s
Why not:
concatMap escapeC s
darcs-2.1.2\src\CommandLine.lhs:103:1: Warning: Use fewer brackets
Found:
ftable ++ (map (\ (c, x) -> (toUpper c, urlEncode x)) ftable)
Why not:
ftable ++ map (\ (c, x) -> (toUpper c, urlEncode x)) ftable
darcs-2.1.2\src\Darcs\Patch\Test.lhs:306:1: Error: Use a more efficient monadic variant
Found:
mapM (delete_line (fn2fp f) line) old
Why not:
mapM_ (delete_line (fn2fp f) line) old
... lots more suggestions ...
Each suggestion says which file/line the suggestion relates to, how serious the issue is, a description of the issue, what it found, and what you might want to replace it with. In the case of the first hint, it has suggested that instead of applying concat and map separately, it would be better to use the combination function concatMap.
The first suggestion is marked as an error, because using concatMap in preference to the two separate functions is always desirable. In contrast, the removal of brackets is probably a good idea, but not always. Reasons that a hint might be a warning include requiring an additional import, something not everyone agrees on, and functions only available in more recent versions of the base library.
Bug reports: The suggested replacement should be equivalent - please report all incorrect suggestions not mentioned as known limitations.
Reports
HLint can generate a lot of information, making it difficult to search for particular types of errors. The --report flag will cause HLint to generate a report file in HTML, which can be viewed interactively. Reports are recommended when there are more than a handlful of hints.
Language Extensions
HLint enables most Haskell extensions, disabling only those which steal too much syntax (currently Arrows, TransformListComp, XmlSyntax and RegularPatterns). Individual extensions can be enabled or disabled with, for instance, -XArrows, or -XNoMagicHash. The flag -XHaskell98 selects Haskell 98 compatibility.
Emacs Integration
Emacs integration has been provided by Alex Ott. The integration is similar to compilation-mode, allowing navigation between errors. The script is at hs-lint.el, and a copy is installed locally in the data directory. To use, add the following code to the Emacs init file:
(require 'hs-lint)
(defun my-haskell-mode-hook ()
(local-set-key "\C-cl" 'hs-lint))
(add-hook 'haskell-mode-hook 'my-haskell-mode-hook)
GHCi Integration
GHCi integration has been provided by Gwern Branwen. The integration allows running :hlint from the GHCi prompt. The script is at hlint.ghci, and a copy is installed locally in the data directory. To use, add the contents to your GHCi startup file.
Parallel Operation
To run HLint on n processors append the flags +RTS -Nn, as described in the GHC user manual. HLint will usually perform fastest if n is equal to the number of physical processors.
If your version of GHC does not support the GHC threaded runtime then install with the command: cabal install --flags="-threaded"
C preprocessor support
HLint runs the cpphs C preprocessor over all input files, by default using the current directory as the include path with no defined macros. These settings can be modified using the flags --cpp-include and --cpp-define. To disable the C preprocessor use the flag -XNoCPP. There are a number of limitations to the C preprocessor support:
- HLint will only check one branch of an #if, based on which macros have been defined.
- Any missing #include files will produce a warning on the console, but no information in the reports.
Unicode support
When compiled with GHC 6.10, HLint only supports ASCII. When compiled with GHC 6.12 or above, HLint uses the current locale encoding. The encoding can be overriden with either --utf8 or --encoding=value. For descriptions of some valid encodings see the mkTextEncoding documentation.
FAQ
Why are suggestions not applied recursively?
Consider:
foo xs = concat (map op xs)
This will suggest eta reduction to concat . map op, and then after making that change and running HLint again, will suggest use of concatMap. Many people wonder why HLint doesn't directly suggest concatMap op. There are a number of reasons:
- HLint aims to both improve code, and to teach the author better style. Doing modifications individually helps this process.
- Sometimes the steps are reasonably complex, by automatically composing them the user may become confused.
- Sometimes HLint gets transformations wrong. If suggestions are applied recursively, one error will cascade.
- Some people only make use of some of the suggestions. In the above example using concatMap is a good idea, but sometimes eta reduction isn't. By suggesting them separately, people can pick and choose.
- Sometimes a transformed expression will be large, and a further hint will apply to some small part of the result, which appears confusing.
- Consider f $ (a b). There are two valid hints, either remove the $ or remove the brackets, but only one can be applied.
Why aren't the suggestions automatically applied?
If you want to automatically apply suggestions, the Emacs integration offers such a feature. However, there are a number of reasons that HLint itself doesn't have an option to automatically apply suggestions:
- The underlying Haskell parser library makes it hard to modify the code, then print it similarly to the original.
- Sometimes multiple transformations may apply.
- After applying one transformation, others that were otherwise suggested may become inappropriate.
I am intending to develop such a feature, but the above reasons mean it is likely to take some time.
Why doesn't the compiler automatically apply the optimisations?
HLint doesn't suggest optimisations, it suggests code improvements - the intention is to make the code simpler, rather than making the code perform faster. The GHC compiler automatically applies many of the rules suggested by HLint, so HLint suggestions will rarely improve performance.
Why doesn't HLint know the fixity for my custom !@%$ operator?
HLint knows the fixities for all the operators in the base library, but no others. HLint works on a single file at a time, and does not resolve imports, so cannot see fixity declarations from imported modules. You can tell HLint about fixities by putting them in a hint file, or passing them on the command line. For example, pass "--with=infixr 5 !@%$", or put all the fixity declarations in a file and pass --hint=fixities.hs. You can also use --find to automatically produce a list of fixity declarations in a file.
How can I use --with or --hint with the default hints?
HLint does not use the default set of hints if custom hints are specified on the command line using --with or --hint. To include the default hints either pass --hint=HLint on the command line, or add import "hint" HLint.HLint in one of the hint files you specify with --hint.
Why do I sometimes get a "Note" with my hint?
Most hints are perfect substitutions, and these are displayed without any notes. However, some hints change the semantics of your program - typically in irrelevant ways - but HLint shows a warning note. HLint does not warn when assuming typeclass laws (such as == being symmetric). Some notes you may see include:
- Increases laziness - for example foldl (&&) True suggests and including this note. The new code will work on infinite lists, while the old code would not. Increasing laziness is usually a good idea.
- Decreases laziness - for example (fst a, snd a) suggests a including this note. On evaluation the new code will raise an error if a is an error, while the old code would produce a pair containing two error values. Only a small number of hints decrease laziness, and anyone relying on the laziness of the original code would be advised to include a comment.
- Removes error - for example foldr1 (&&) suggests and including the note "Removes error on []". The new code will produce True on the empty list, while the old code would raise an error. Unless you are relying on the exception thrown by the empty list, this hint is safe - and if you do rely on the exception, you would be advised to add a comment.
What is the difference between error and warning?
Every hint has a severity level:
- Error - for example concat (map f x) suggests concatMap f x as an "error" severity hint. From a style point of view, you should always replace a combination of concat and map with concatMap. Note that both expressions are equivalent - HLint is reporting an error in style, not an actual error in the code.
- Warning - for example x !! 0 suggests head x as a "warning" severity hint. Typically head is a simpler way of expressing the first element of a list, especially if you are treating the list inductively. However, in the expression f (x !! 4) (x !! 0) (x !! 7), replacing the middle argument with head makes it harder to follow the pattern, and is probably a bad idea. Warning hints are often worthwhile, but should not be applied blindly.
The difference between error and warning is one of personal taste, typically my personal taste. If you already have a well developed sense of Haskell style, you should ignore the difference. If you are a beginner Haskell programmer you may wish to focus on error hints before warning hints.
Customizing the hints
Many of the hints that are applied by HLint are contained in Haskell source files which are installed in the data directory by Cabal. These files may be edited, to add library specific knowledge, to include hints that may have been missed, or to ignore unwanted hints.
Choosing a package of hints
By default, HLint will use the HLint.hs file either from the current working directory, or from the data directory. Alternatively, hint files can be specified with the --hint flag. HLint comes with a number of hint packages:
- Default - these are the hints that are used by default, covering most of the base libraries.
- Dollar - suggests the replacement a $ b $ c with a . b $ c. This hint is especially popular on the #haskell IRC channel.
- Generalise - suggests replacing specific variants of functions (i.e. map) with more generic functions (i.e. fmap).
As an example, to check the file Example.hs with both the default hints and the dollar hint, I could type: hlint Example.hs --hint=Default --hint=Dollar. Alternatively, I could create the file HLint.hs in the working directory and give it the contents:
import "hint" HLint.Default
import "hint" HLint.Dollar
Ignoring hints
Some of the hints are subjective, and some users believe they should be ignored. Some hints are applicable usually, but occasionally don't always make sense. The ignoring mechanism provides features for supressing certain hints. Ignore directives can either be written as pragmas in the file being analysed, or in the hint files. Examples of pragmas are:
- {-# ANN module "HLint: ignore Eta reduce" #-} - ignore all eta reduction suggestions in this module.
- {-# ANN myFunction "HLint: ignore" #-} - don't give any hints in the function myFunction.
- {-# ANN myFunction "HLint: error" #-} - any hint in the function myFunction is an error.
- {-# ANN module "HLint: error Use concatMap" #-} - the hint to use concatMap is an error.
- {-# ANN module "HLint: warn Use concatMap" #-} - the hint to use concatMap is a warning.
Ignore directives can also be written in the hint files:
- ignore "Eta reduce" - supress all eta reduction suggestions.
- ignore "Eta reduce" = MyModule1 MyModule2 - supress eta reduction hints in the MyModule1 and MyModule2 modules.
- ignore = MyModule.myFunction - don't give any hints in the function MyModule.myFunction.
- error = MyModule.myFunction - any hint in the function MyModule.myFunction is an error.
- error "Use concatMap" - the hint to use concatMap is an error.
- warn "Use concatMap" - the hint to use concatMap is a warning.
These directives are applied in the order they are given, with later hints overriding earlier ones.
Adding hints
The hint suggesting concatMap is defined as:
error = concat (map f x) ==> concatMap f x
The line can be read as replace concat (map f x) with concatMap f x. All single-letter variables are treated as substitution parameters. For examples of more complex hints see the supplied hints file. In general, hints should not be given in point free style, as this reduces the power of the matching. Hints may start with error or warn to denote how severe they are by default. If you come up with interesting hints, please submit them for inclusion.
You can search for possible hints to add from a source file with the --find flag, for example:
$ hlint --find=src/Utils.hs
-- hints found in src/Util.hs
warn = null (intersect a b) ==> disjoint a b
warn = dropWhile isSpace ==> ltrim
infixr 5 !:
These hints are suitable for inclusion in a custom hint file. You can also include Haskell fixity declarations in a hint file, and these will also be extracted. If you pass only --find flags then the hints will be written out, if you also pass files/folders to check, then the found hints will be automatically used when checking.
hlint-1.8.53/hlint.cabal 0000644 0000000 0000000 00000004127 12220306165 013217 0 ustar 00 0000000 0000000 cabal-version: >= 1.6
build-type: Simple
name: hlint
version: 1.8.53
license: BSD3
license-file: LICENSE
category: Development
author: Neil Mitchell
maintainer: Neil Mitchell
copyright: Neil Mitchell 2006-2013
synopsis: Source code suggestions
description:
HLint gives suggestions on how to improve your source code.
homepage: http://community.haskell.org/~ndm/hlint/
stability: Beta
data-dir: data
data-files:
Default.hs
Generalise.hs
Dollar.hs
HLint.hs
Test.hs
report_template.html
hs-lint.el
hlint.1
hlint.ghci
extra-source-files:
hlint.htm
source-repository head
type: git
location: git://github.com/ndmitchell/hlint.git
flag threaded
default: True
description: Build with support for multithreaded execution
library
build-depends:
base == 4.*, process, filepath, directory, containers,
transformers >= 0.0,
hscolour >= 1.17,
cpphs >= 1.11,
haskell-src-exts >= 1.14 && < 1.15,
uniplate >= 1.5
hs-source-dirs: src
exposed-modules:
Language.Haskell.HLint
other-modules:
Paths_hlint
Apply
CmdLine
HLint
Idea
Settings
Report
Proof
Test
Util
Parallel
HSE.All
HSE.Bracket
HSE.Evaluate
HSE.FreeVars
HSE.Match
HSE.NameMatch
HSE.Type
HSE.Util
Hint.All
Hint.Bracket
Hint.Duplicate
Hint.Extensions
Hint.Import
Hint.Lambda
Hint.List
Hint.ListRec
Hint.Match
Hint.Monad
Hint.Naming
Hint.Pragma
Hint.Structure
Hint.Type
Hint.Util
executable hlint
build-depends: base
hs-source-dirs: src
main-is: Main.hs
ghc-options: -fno-warn-overlapping-patterns
if flag(threaded)
ghc-options: -threaded
hlint-1.8.53/src/ 0000755 0000000 0000000 00000000000 12220306165 011700 5 ustar 00 0000000 0000000 hlint-1.8.53/src/Util.hs 0000644 0000000 0000000 00000016712 12220306165 013160 0 ustar 00 0000000 0000000 {-# LANGUAGE CPP, ExistentialQuantification, Rank2Types, PatternGuards #-}
module Util where
import Control.Arrow
import Control.Monad
import Control.Monad.Trans.State
import Control.Exception
import Data.Char
import Data.Function
import Data.List
import Data.Ord
import System.Directory
import System.Exit
import System.FilePath
import System.IO
import System.IO.Unsafe
import Unsafe.Coerce
import Data.Data
import Data.Generics.Uniplate.Operations
import Language.Haskell.Exts.Extension
#if __GLASGOW_HASKELL__ >= 612
import GHC.IO.Handle(hDuplicate,hDuplicateTo)
#endif
---------------------------------------------------------------------
-- SYSTEM.DIRECTORY
getDirectoryContentsRecursive :: FilePath -> IO [FilePath]
getDirectoryContentsRecursive dir = do
xs <- getDirectoryContents dir
(dirs,files) <- partitionM doesDirectoryExist [dir > x | x <- xs, not $ isBadDir x]
rest <- concatMapM getDirectoryContentsRecursive dirs
return $ files++rest
where
isBadDir x = "." `isPrefixOf` x || "_" `isPrefixOf` x
---------------------------------------------------------------------
-- CONTROL.MONAD
partitionM :: Monad m => (a -> m Bool) -> [a] -> m ([a], [a])
partitionM f [] = return ([], [])
partitionM f (x:xs) = do
res <- f x
(as,bs) <- partitionM f xs
return ([x | res]++as, [x | not res]++bs)
concatMapM :: Monad m => (a -> m [b]) -> [a] -> m [b]
concatMapM f = liftM concat . mapM f
concatM :: Monad m => [m [a]] -> m [a]
concatM = liftM concat . sequence
concatZipWithM :: Monad m => (a -> b -> m [c]) -> [a] -> [b] -> m [c]
concatZipWithM f xs ys = liftM concat $ zipWithM f xs ys
listM' :: Monad m => [a] -> m [a]
listM' x = length x `seq` return x
---------------------------------------------------------------------
-- PRELUDE
notNull = not . null
headDef :: a -> [a] -> a
headDef x [] = x
headDef x (y:ys) = y
isLeft_ Left{} = True; isLeft_ _ = False
isRight_ = not . isLeft_
unzipEither :: [Either a b] -> ([a], [b])
unzipEither (x:xs) = case x of
Left y -> (y:a,b)
Right y -> (a,y:b)
where (a,b) = unzipEither xs
unzipEither [] = ([], [])
for = flip map
---------------------------------------------------------------------
-- DATA.STRING
limit :: Int -> String -> String
limit n s = if null post then s else pre ++ "..."
where (pre,post) = splitAt n s
ltrim :: String -> String
ltrim = dropWhile isSpace
trimBy :: (a -> Bool) -> [a] -> [a]
trimBy f = reverse . dropWhile f . reverse . dropWhile f
---------------------------------------------------------------------
-- DATA.LIST
groupSortFst :: Ord a => [(a,b)] -> [(a,[b])]
groupSortFst = map (fst . head &&& map snd) . groupBy ((==) `on` fst) . sortBy (comparing fst)
disjoint :: Eq a => [a] -> [a] -> Bool
disjoint xs = null . intersect xs
unsnoc :: [a] -> ([a],a)
unsnoc [] = error "Unsnoc on empty list"
unsnoc xs = (init xs, last xs)
revTake :: Int -> [a] -> [a]
revTake i = reverse . take i . reverse
concatUnzip :: [([a], [b])] -> ([a], [b])
concatUnzip = (concat *** concat) . unzip
---------------------------------------------------------------------
-- DATA.TUPLE
swap :: (a,b) -> (b,a)
swap (a,b) = (b,a)
---------------------------------------------------------------------
-- SYSTEM.IO
-- | An encoding is a function to change a handle to a particular encoding
data Encoding = Encoding_Internal (Maybe (Handle -> IO ()))
defaultEncoding :: Encoding
defaultEncoding = Encoding_Internal Nothing
readFileEncoding :: Encoding -> FilePath -> IO String
readFileEncoding (Encoding_Internal x) file = case x of
Nothing -> if file == "-" then getContents else readFile file
Just set -> do
h <- if file == "-" then return stdin else openFile file ReadMode
set h
hGetContents h
-- GHC's mkTextEncoding function is fairly poor - it doesn't support lots of fun things,
-- so we fake them up, and then try mkTextEncoding last
newEncoding :: String -> IO Encoding
newEncoding "" = return defaultEncoding
#if __GLASGOW_HASKELL__ >= 612
newEncoding enc
| Just e <- lookup (f enc) [(f a, b) | (as,b) <- encs, a <- as] = return $ wrap e
| otherwise = do
res <- try $ mkTextEncoding enc :: IO (Either SomeException TextEncoding)
case res of
Right e -> return $ wrap e
Left _ -> do
let (a,b) = splitAt 2 $ map (head . fst) encs
putStr $ unlines
["Error: Unknown text encoding argument, " ++ enc
,"Possible values:"
," " ++ unwords a
," " ++ unwords b
," and anything accepted by System.IO.mkTextEncoding"]
exitWith $ ExitFailure 1
where
f = map toLower . filter (`notElem` "-_ ")
wrap = Encoding_Internal . Just . flip hSetEncoding
encs = let a*b = (words a, b)
in ["ISO8859-1 8859-1 ISO8859 8859 LATIN LATIN1" * latin1
,"LOCALE" * localeEncoding
,"UTF-8" * utf8
,"UTF-8BOM" * utf8_bom
,"UTF-16" * utf16
,"UTF-16LE" * utf16le
,"UTF-16BE" * utf16be
,"UTF-32" * utf16
,"UTF-32LE" * utf16le
,"UTF-32BE" * utf16be]
#else
newEncoding enc = do
putStrLn "Warning: Text encodings are not supported with HLint compiled by GHC 6.10"
return defaultEncoding
#endif
exitMessage :: String -> a
exitMessage msg = unsafePerformIO $ do
putStrLn msg
exitWith $ ExitFailure 1
-- FIXME: This could use a lot more bracket calls!
captureOutput :: IO () -> IO (Maybe String)
#if __GLASGOW_HASKELL__ < 612
captureOutput act = return Nothing
#else
captureOutput act = do
tmp <- getTemporaryDirectory
(f,h) <- openTempFile tmp "hlint"
sto <- hDuplicate stdout
ste <- hDuplicate stderr
hDuplicateTo h stdout
hDuplicateTo h stderr
hClose h
act
hDuplicateTo sto stdout
hDuplicateTo ste stderr
res <- readFile' f
removeFile f
return $ Just res
#endif
-- FIXME: Should use strict ByteString
readFile' :: FilePath -> IO String
readFile' x = listM' =<< readFile x
---------------------------------------------------------------------
-- DATA.GENERICS
data Box = forall a . Data a => Box a
gzip :: Data a => (forall b . Data b => b -> b -> c) -> a -> a -> Maybe [c]
gzip f x y | toConstr x /= toConstr y = Nothing
| otherwise = Just $ zipWith op (gmapQ Box x) (gmapQ Box y)
where op (Box x) (Box y) = f x (unsafeCoerce y)
---------------------------------------------------------------------
-- DATA.GENERICS.UNIPLATE.OPERATIONS
descendIndex :: Uniplate a => (Int -> a -> a) -> a -> a
descendIndex f x = flip evalState 0 $ flip descendM x $ \y -> do
i <- get
modify (+1)
return $ f i y
universeParent :: Uniplate a => a -> [(Maybe a, a)]
universeParent x = (Nothing,x) : f x
where
f :: Uniplate a => a -> [(Maybe a, a)]
f x = concat [(Just x, y) : f y | y <- children x]
universeParentBi :: Biplate a b => a -> [(Maybe b, b)]
universeParentBi = concatMap universeParent . childrenBi
---------------------------------------------------------------------
-- LANGUAGE.HASKELL.EXTS.EXTENSION
defaultExtensions :: [Extension]
defaultExtensions = [e | e@EnableExtension{} <- knownExtensions] \\ map EnableExtension badExtensions
badExtensions =
[Arrows -- steals proc
,TransformListComp -- steals the group keyword
,XmlSyntax, RegularPatterns -- steals a-b
]
hlint-1.8.53/src/Test.hs 0000644 0000000 0000000 00000021752 12220306165 013162 0 ustar 00 0000000 0000000 {-# LANGUAGE PatternGuards, ScopedTypeVariables, RecordWildCards #-}
module Test(test) where
import Control.Exception
import Control.Monad
import Data.Char
import Data.List
import Data.Maybe
import Data.Monoid
import Data.Function
import System.Directory
import System.FilePath
import System.IO
import System.Cmd
import System.Exit
import Settings
import Util
import Idea
import Apply
import HSE.All
import Hint.All
data Result = Result {_failures :: Int, _total :: Int}
pass = Result 0 1
failure = Result 1 1
result x = if x then pass else failure
results = fmap mconcat
instance Monoid Result where
mempty = Result 0 0
mappend (Result f1 t1) (Result f2 t2) = Result (f1+f2) (t1+t2)
progress = putChar '.'
failed xs = putStrLn $ unlines $ "" : xs
test :: ([String] -> IO ()) -> FilePath -> [FilePath] -> IO Int
test main dataDir files = do
Result failures total <-
if null files then do
src <- doesFileExist "hlint.cabal"
res <- results $ sequence $ (if src then id else take 1)
[testHintFiles dataDir, testSourceFiles, testInputOutput main]
putStrLn ""
unless src $ putStrLn "Warning, couldn't find source code, so non-hint tests skipped"
return res
else do
res <- results $ mapM (testHintFile dataDir) files
putStrLn ""
return res
putStrLn $ if failures == 0
then "Tests passed (" ++ show total ++ ")"
else "Tests failed (" ++ show failures ++ " of " ++ show total ++ ")"
return failures
testHintFiles :: FilePath -> IO Result
testHintFiles dataDir = do
xs <- getDirectoryContents dataDir
results $ mapM (testHintFile dataDir)
[dataDir > x | x <- xs, takeExtension x == ".hs", not $ "HLint" `isPrefixOf` takeBaseName x]
testHintFile :: FilePath -> FilePath -> IO Result
testHintFile dataDir file = do
hints <- readSettings dataDir [file] []
res <- results $ sequence $ nameCheckHints hints : checkAnnotations hints file :
[typeCheckHints hints | takeFileName file /= "Test.hs"]
progress
return res
testSourceFiles :: IO Result
testSourceFiles = fmap mconcat $ sequence
[checkAnnotations [Builtin name] ("src/Hint" > name <.> "hs") | (name,h) <- staticHints]
testInputOutput :: ([String] -> IO ()) -> IO Result
testInputOutput main = do
xs <- getDirectoryContents "tests"
results $ mapM (checkInputOutput main) $ groupBy ((==) `on` takeBaseName) $ sort $ filter (not . isPrefixOf ".") xs
---------------------------------------------------------------------
-- VARIOUS SMALL TESTS
nameCheckHints :: [Setting] -> IO Result
nameCheckHints hints = do
let bad = [failed ["No name for the hint " ++ prettyPrint (lhs x)] | x@MatchExp{} <- hints, hintS x == defaultHintName]
sequence_ bad
return $ Result (length bad) 0
-- | Given a set of hints, do all the MatchExp hints type check
typeCheckHints :: [Setting] -> IO Result
typeCheckHints hints = bracket
(openTempFile "." "hlinttmp.hs")
(\(file,h) -> removeFile file)
$ \(file,h) -> do
hPutStrLn h $ unlines contents
hClose h
res <- system $ "runhaskell " ++ file
progress
return $ result $ res == ExitSuccess
where
matches = filter isMatchExp hints
-- Hack around haskell98 not being compatible with base anymore
hackImport i@ImportDecl{importAs=Just a,importModule=b}
| prettyPrint b `elem` words "Maybe List Monad IO Char" = i{importAs=Just b,importModule=a}
hackImport i = i
contents =
["{-# LANGUAGE NoMonomorphismRestriction, ExtendedDefaultRules #-}"] ++
concat [map (prettyPrint . hackImport) $ scopeImports $ scope x | x <- take 1 matches] ++
["main = return ()"
,"(==>) :: a -> a -> a; (==>) = undefined"
,"_noParen_ = id"
,"_eval_ = id"] ++
["{-# LINE " ++ show (startLine $ ann rhs) ++ " " ++ show (fileName $ ann rhs) ++ " #-}\n" ++
prettyPrint (PatBind an (toNamed $ "test" ++ show i) Nothing bod Nothing)
| (i, MatchExp _ _ _ lhs rhs side _) <- zip [1..] matches, "notTypeSafe" `notElem` vars (maybeToList side)
, let vs = map toNamed $ nub $ filter isUnifyVar $ vars lhs ++ vars rhs
, let inner = InfixApp an (Paren an lhs) (toNamed "==>") (Paren an rhs)
, let bod = UnGuardedRhs an $ if null vs then inner else Lambda an vs inner]
---------------------------------------------------------------------
-- CHECK ANNOTATIONS
-- Input, Output
-- Output = Nothing, should not match
-- Output = Just xs, should match xs
data Test = Test SrcLoc String (Maybe String)
checkAnnotations :: [Setting] -> FilePath -> IO Result
checkAnnotations setting file = do
tests <- parseTestFile file
failures <- concatMapM f tests
sequence_ failures
return $ Result (length failures) (length tests)
where
f (Test loc inp out) = do
ideas <- applyHintString parseFlags setting file inp
let good = case out of
Nothing -> null ideas
Just x -> length ideas == 1 &&
seq (length (show ideas)) True && -- force, mainly for hpc
not (isParseError (head ideas)) &&
match x (head ideas)
return $
[failed $
["TEST FAILURE (" ++ show (length ideas) ++ " hints generated)"
,"SRC: " ++ showSrcLoc loc
,"INPUT: " ++ inp] ++
map ((++) "OUTPUT: " . show) ideas ++
["WANTED: " ++ fromMaybe "" out]
| not good] ++
[failed
["TEST FAILURE (BAD LOCATION)"
,"SRC: " ++ showSrcLoc loc
,"INPUT: " ++ inp
,"OUTPUT: " ++ show i]
| i@Idea{loc=SrcLoc{..}} <- ideas, srcFilename == "" || srcLine == 0 || srcColumn == 0]
match "???" _ = True
match x y | "@" `isPrefixOf` x = a == show (severity y) && match (ltrim b) y
where (a,b) = break isSpace $ tail x
match x y = on (==) norm (to y) x
-- FIXME: Should use a better check for expected results
norm = filter $ \x -> not (isSpace x) && x /= ';'
parseTestFile :: FilePath -> IO [Test]
parseTestFile file = do
src <- readFile file
return $ f False $ zip [1..] $ lines src
where
open = isPrefixOf ""
shut = isPrefixOf ""
f False ((i,x):xs) = f (open x) xs
f True ((i,x):xs)
| shut x = f False xs
| null x || "--" `isPrefixOf` x = f True xs
| "\\" `isSuffixOf` x, (_,y):ys <- xs = f True $ (i,init x++"\n"++y):ys
| otherwise = parseTest file i x : f True xs
f _ [] = []
parseTest file i x = Test (SrcLoc file i 0) x $
case dropWhile (/= "--") $ words x of
[] -> Nothing
_:xs -> Just $ unwords xs
---------------------------------------------------------------------
-- CHECK INPUT/OUTPUT PAIRS
checkInputOutput :: ([String] -> IO ()) -> [FilePath] -> IO Result
checkInputOutput main xs = do
let pre = takeBaseName $ head xs
has x = (pre <.> x) `elem` xs
reader x = readFile' $ "tests" > pre <.> x
flags <-
if has "flags" then fmap lines $ reader "flags"
else if has "hs" then return ["tests/" ++ pre <.> "hs"]
else if has "lhs" then return ["tests/" ++ pre <.> "lhs"]
else error "checkInputOutput, couldn't find or figure out flags"
got <- fmap (fmap lines) $ captureOutput $
handle (\(e::SomeException) -> print e) $
handle (\(e::ExitCode) -> return ()) $
main flags
let gotValid = isJust got
want <- fmap lines $ reader "output"
(want,got) <- return $ matchStarStar want $ fromMaybe [] got
if not gotValid then
putStrLn "Warning: failed to capture output (GHC too old?)" >> return pass
else if length got == length want && and (zipWith matchStar want got) then
return pass
else do
let trail = replicate (max (length got) (length want)) ""
let (i,g,w):_ = [(i,g,w) | (i,g,w) <- zip3 [1..] (got++trail) (want++trail), not $ matchStar w g]
putStrLn $ unlines
["TEST FAILURE IN tests/" ++ pre
,"DIFFER ON LINE: " ++ show i
,"GOT : " ++ g
,"WANT: " ++ w]
when (null want) $ putStrLn $ unlines $ "FULL OUTPUT FOR GOT:" : got
return failure
-- | First string may have stars in it (the want)
matchStar :: String -> String -> Bool
matchStar ('*':xs) ys = any (matchStar xs) $ tails ys
matchStar (x:xs) (y:ys) = x == y && matchStar xs ys
matchStar [] [] = True
matchStar _ _ = False
matchStarStar :: [String] -> [String] -> ([String], [String])
matchStarStar want got = case break (== "**") want of
(_, []) -> (want, got)
(w1,_:w2) -> (w1++w2, g1 ++ revTake (length w2) g2)
where (g1,g2) = splitAt (length w1) got
hlint-1.8.53/src/Settings.hs 0000644 0000000 0000000 00000024033 12220306165 014036 0 ustar 00 0000000 0000000 {-# LANGUAGE PatternGuards, ViewPatterns #-}
module Settings(
Severity(..), Note(..), showNotes, FuncName, Setting(..), isClassify, isMatchExp,
defaultHintName, isUnifyVar,
readSettings, readPragma, findSettings
) where
import HSE.All
import Data.Char
import Data.List
import System.FilePath
import Util
defaultHintName = "Use alternative"
-- | How severe an error is.
data Severity
= Ignore -- ^ Ignored errors are only returned when @--show@ is passed.
| Warning -- ^ Warnings are things that some people may consider improvements, but some may not.
| Error -- ^ Errors are suggestions that should nearly always be a good idea to apply.
deriving (Eq,Ord,Show,Read,Bounded,Enum)
getSeverity :: String -> Maybe Severity
getSeverity "ignore" = Just Ignore
getSeverity "warn" = Just Warning
getSeverity "warning" = Just Warning
getSeverity "error" = Just Error
getSeverity "hint" = Just Error
getSeverity _ = Nothing
-- (modulename,functionname)
-- either being blank implies universal matching
type FuncName = (String,String)
-- Any 1-letter variable names are assumed to be unification variables
isUnifyVar :: String -> Bool
isUnifyVar [x] = x == '?' || isAlpha x
isUnifyVar _ = False
addInfix x = x{infixes = infix_ (-1) ["==>"] ++ infixes x}
---------------------------------------------------------------------
-- TYPE
data Note
= IncreasesLaziness
| DecreasesLaziness
| RemovesError String -- RemovesError "on []", RemovesError "when x is negative"
| ValidInstance String String -- ValidInstance "Eq" "x"
| Note String
deriving (Eq,Ord)
instance Show Note where
show IncreasesLaziness = "increases laziness"
show DecreasesLaziness = "decreases laziness"
show (RemovesError x) = "removes error " ++ x
show (ValidInstance x y) = "requires a valid " ++ x ++ " instance for " ++ y
show (Note x) = x
showNotes :: [Note] -> String
showNotes = intercalate ", " . map show . filter use
where use ValidInstance{} = False -- Not important enough to tell an end user
use _ = True
data Setting
= Classify {severityS :: Severity, hintS :: String, funcS :: FuncName}
| MatchExp {severityS :: Severity, hintS :: String, scope :: Scope, lhs :: Exp_, rhs :: Exp_, side :: Maybe Exp_, notes :: [Note]}
| Builtin String -- use a builtin hint set
| Infix Fixity
deriving Show
isClassify Classify{} = True; isClassify _ = False
isMatchExp MatchExp{} = True; isMatchExp _ = False
---------------------------------------------------------------------
-- READ A SETTINGS FILE
-- Given a list of hint files to start from
-- Return the list of settings commands
readSettings :: FilePath -> [FilePath] -> [String] -> IO [Setting]
readSettings dataDir files hints = do
(builtin,mods) <- fmap unzipEither $ concatMapM (readHints dataDir) $ map Right files ++ map Left hints
let f m = concatMap (readSetting $ moduleScope m) $ concatMap getEquations $ moduleDecls m
return $ map Builtin builtin ++ concatMap f mods
-- Read a hint file, and all hint files it imports
readHints :: FilePath -> Either String FilePath -> IO [Either String Module_]
readHints dataDir file = do
let flags = addInfix parseFlags
y <- parseResult $ either (parseString flags "CommandLine") (parseFile flags) file
ys <- concatM [f $ fromNamed $ importModule i | i <- moduleImports y, importPkg i `elem` [Just "hint", Just "hlint"]]
return $ Right y:ys
where
f x | "HLint.Builtin." `isPrefixOf` x = return [Left $ drop 14 x]
| "HLint." `isPrefixOf` x = readHints dataDir $ Right $ dataDir > drop 6 x <.> "hs"
| otherwise = readHints dataDir $ Right $ x <.> "hs"
readSetting :: Scope -> Decl_ -> [Setting]
readSetting s (FunBind _ [Match _ (Ident _ (getSeverity -> Just severity)) pats (UnGuardedRhs _ bod) bind])
| InfixApp _ lhs op rhs <- bod, opExp op ~= "==>" =
let (a,b) = readSide $ childrenBi bind in
[MatchExp severity (headDef defaultHintName names) s (fromParen lhs) (fromParen rhs) a b]
| otherwise = [Classify severity n func | n <- names2, func <- readFuncs bod]
where
names = filter notNull $ getNames pats bod
names2 = ["" | null names] ++ names
readSetting s x | "test" `isPrefixOf` map toLower (fromNamed x) = []
readSetting s x@AnnPragma{} | Just y <- readPragma x = [y]
readSetting s (PatBind an (PVar _ name) _ bod bind) = readSetting s $ FunBind an [Match an name [] bod bind]
readSetting s (FunBind an xs) | length xs /= 1 = concatMap (readSetting s . FunBind an . return) xs
readSetting s (SpliceDecl an (App _ (Var _ x) (Lit _ y))) = readSetting s $ FunBind an [Match an (toNamed $ fromNamed x) [PLit an y] (UnGuardedRhs an $ Lit an $ String an "" "") Nothing]
readSetting s x@InfixDecl{} = map Infix $ getFixity x
readSetting s x = errorOn x "bad hint"
-- return Nothing if it is not an HLint pragma, otherwise all the settings
readPragma :: Decl_ -> Maybe Setting
readPragma o@(AnnPragma _ p) = f p
where
f (Ann _ name x) = g (fromNamed name) x
f (TypeAnn _ name x) = g (fromNamed name) x
f (ModuleAnn _ x) = g "" x
g name (Lit _ (String _ s _)) | "hlint:" `isPrefixOf` map toLower s =
case getSeverity a of
Nothing -> errorOn o "bad classify pragma"
Just severity -> Just $ Classify severity (ltrim b) ("",name)
where (a,b) = break isSpace $ ltrim $ drop 6 s
g name (Paren _ x) = g name x
g name (ExpTypeSig _ x _) = g name x
g _ _ = Nothing
readPragma _ = Nothing
readSide :: [Decl_] -> (Maybe Exp_, [Note])
readSide = foldl f (Nothing,[])
where f (Nothing,notes) (PatBind _ PWildCard{} Nothing (UnGuardedRhs _ side) Nothing) = (Just side, notes)
f (Nothing,notes) (PatBind _ (fromNamed -> "side") Nothing (UnGuardedRhs _ side) Nothing) = (Just side, notes)
f (side,[]) (PatBind _ (fromNamed -> "note") Nothing (UnGuardedRhs _ note) Nothing) = (side,g note)
f _ x = errorOn x "bad side condition"
g (Lit _ (String _ x _)) = [Note x]
g (List _ xs) = concatMap g xs
g x = case fromApps x of
[con -> Just "IncreasesLaziness"] -> [IncreasesLaziness]
[con -> Just "DecreasesLaziness"] -> [DecreasesLaziness]
[con -> Just "RemovesError",str -> Just a] -> [RemovesError a]
[con -> Just "ValidInstance",str -> Just a,var -> Just b] -> [ValidInstance a b]
_ -> errorOn x "bad note"
con :: Exp_ -> Maybe String
con c@Con{} = Just $ prettyPrint c; con _ = Nothing
var c@Var{} = Just $ prettyPrint c; var _ = Nothing
str c = if isString c then Just $ fromString c else Nothing
-- Note: Foo may be ("","Foo") or ("Foo",""), return both
readFuncs :: Exp_ -> [FuncName]
readFuncs (App _ x y) = readFuncs x ++ readFuncs y
readFuncs (Lit _ (String _ "" _)) = [("","")]
readFuncs (Var _ (UnQual _ name)) = [("",fromNamed name)]
readFuncs (Var _ (Qual _ (ModuleName _ mod) name)) = [(mod, fromNamed name)]
readFuncs (Con _ (UnQual _ name)) = [(fromNamed name,""),("",fromNamed name)]
readFuncs (Con _ (Qual _ (ModuleName _ mod) name)) = [(mod ++ "." ++ fromNamed name,""),(mod,fromNamed name)]
readFuncs x = errorOn x "bad classification rule"
getNames :: [Pat_] -> Exp_ -> [String]
getNames ps _ | ps /= [] && all isPString ps = map fromPString ps
getNames [] (InfixApp _ lhs op rhs) | opExp op ~= "==>" = map ("Use "++) names
where
lnames = map f $ childrenS lhs
rnames = map f $ childrenS rhs
names = filter (not . isUnifyVar) $ (rnames \\ lnames) ++ rnames
f (Ident _ x) = x
f (Symbol _ x) = x
getNames _ _ = []
errorOn :: (Annotated ast, Pretty (ast S)) => ast S -> String -> b
errorOn val msg = exitMessage $
showSrcLoc (getPointLoc $ ann val) ++
": Error while reading hint file, " ++ msg ++ "\n" ++
prettyPrint val
---------------------------------------------------------------------
-- FIND SETTINGS IN A SOURCE FILE
-- find definitions in a source file
findSettings :: ParseFlags -> FilePath -> IO (String, [Setting])
findSettings flags file = do
x <- parseFile flags file
case snd x of
ParseFailed sl msg ->
return ("-- Parse error " ++ showSrcLoc sl ++ ": " ++ msg, [])
ParseOk m -> do
let xs = concatMap (findSetting $ UnQual an) (moduleDecls m)
s = unlines $ ["-- hints found in " ++ file] ++ map prettyPrint xs ++ ["-- no hints found" | null xs]
r = concatMap (readSetting emptyScope) xs
return (s,r)
findSetting :: (Name S -> QName S) -> Decl_ -> [Decl_]
findSetting qual (InstDecl _ _ _ (Just xs)) = concatMap (findSetting qual) [x | InsDecl _ x <- xs]
findSetting qual (PatBind _ (PVar _ name) Nothing (UnGuardedRhs _ bod) Nothing) = findExp (qual name) [] bod
findSetting qual (FunBind _ [InfixMatch _ p1 name ps rhs bind]) = findSetting qual $ FunBind an [Match an name (p1:ps) rhs bind]
findSetting qual (FunBind _ [Match _ name ps (UnGuardedRhs _ bod) Nothing]) = findExp (qual name) [] $ Lambda an ps bod
findSetting _ x@InfixDecl{} = [x]
findSetting _ _ = []
-- given a result function name, a list of variables, a body expression, give some hints
findExp :: QName S -> [String] -> Exp_ -> [Decl_]
findExp name vs (Lambda _ ps bod) | length ps2 == length ps = findExp name (vs++ps2) bod
| otherwise = []
where ps2 = [x | PVar_ x <- map view ps]
findExp name vs Var{} = []
findExp name vs (InfixApp _ x dot y) | isDot dot = findExp name (vs++["_hlint"]) $ App an x $ Paren an $ App an y (toNamed "_hlint")
findExp name vs bod = [PatBind an (toNamed "warn") Nothing (UnGuardedRhs an $ InfixApp an lhs (toNamed "==>") rhs) Nothing]
where
lhs = g $ transform f bod
rhs = apps $ Var an name : map snd rep
rep = zip vs $ map (toNamed . return) ['a'..]
f xx | Var_ x <- view xx, Just y <- lookup x rep = y
f (InfixApp _ x dol y) | isDol dol = App an x (paren y)
f x = x
g o@(InfixApp _ _ _ x) | isAnyApp x || isAtom x = o
g o@App{} = o
g o = paren o
hlint-1.8.53/src/Report.hs 0000644 0000000 0000000 00000004776 12220306165 013525 0 ustar 00 0000000 0000000 {-# LANGUAGE RecordWildCards #-}
module Report(writeReport) where
import Idea
import Control.Arrow
import Data.List
import Data.Maybe
import Data.Version
import System.FilePath
import HSE.All
import Paths_hlint
import Language.Haskell.HsColour.CSS
writeTemplate :: FilePath -> [(String,[String])] -> FilePath -> IO ()
writeTemplate dataDir content to = do
src <- readFile $ dataDir > "report_template.html"
writeFile to $ unlines $ concatMap f $ lines src
where
f ('$':xs) = fromMaybe ['$':xs] $ lookup xs content
f x = [x]
writeReport :: FilePath -> FilePath -> [Idea] -> IO ()
writeReport dataDir file ideas = writeTemplate dataDir inner file
where
generateIds :: [String] -> [(String,Int)] -- sorted by name
generateIds = map (head &&& length) . group . sort
files = generateIds $ map (srcFilename . loc) ideas
hints = generateIds $ map hintName ideas
hintName x = show (severity x) ++ ": " ++ hint x
inner = [("VERSION",['v' : showVersion version]),("CONTENT",content),
("HINTS",list "hint" hints),("FILES",list "file" files)]
content = concatMap (\i -> writeIdea (getClass i) i) ideas
getClass i = "hint" ++ f hints (hintName i) ++ " file" ++ f files (srcFilename $ loc i)
where f xs x = show $ fromJust $ findIndex ((==) x . fst) xs
list mode xs = zipWith f [0..] xs
where
f i (name,n) = "" ++
escapeHTML name ++ " (" ++ show n ++ ")"
where id = mode ++ show i
code = hscolour False
writeIdea :: String -> Idea -> [String]
writeIdea cls Idea{..} =
[""
,escapeHTML (showSrcLoc loc ++ ": " ++ show severity ++ ": " ++ hint) ++ "
"
,"Found
"
,code from
,"Why not" ++ (if to == "" then " remove it." else "") ++ "
"
,code to
,let n = showNotes note in if n /= "" then "Note: " ++ n ++ "" else ""
,"
"
,""]
writeIdea cls ParseError{..} =
[""
,escapeHTML (showSrcLoc loc ++ ": " ++ show severity ++ ": " ++ hint) ++ "
"
,"Error message
"
,"
" ++ escapeHTML msg ++ "
"
,"Code
"
,code from
,"
"
,""]
escapeHTML :: String -> String
escapeHTML = concatMap f
where
f '>' = ">"
f '<' = "<"
f '&' = "&"
f x = [x]
hlint-1.8.53/src/Proof.hs 0000644 0000000 0000000 00000020457 12220306165 013331 0 ustar 00 0000000 0000000 {-# LANGUAGE RecordWildCards, PatternGuards #-}
module Proof(proof) where
import Control.Arrow
import Control.Monad
import Control.Monad.Trans.State
import Data.Char
import Data.List
import Data.Maybe
import Data.Function
import System.FilePath
import Settings
import HSE.All
data Theorem = Theorem
{original :: Maybe Setting
,location :: String
,lemma :: String
}
instance Eq Theorem where
t1 == t2 = lemma t1 == lemma t2
instance Show Theorem where
show Theorem{..} = location ++ ":\n" ++ maybe "" f original ++ lemma ++ "\n"
where f MatchExp{..} = "(* " ++ prettyPrint lhs ++ " ==> " ++ prettyPrint rhs ++ " *)\n"
proof :: [FilePath] -> [Setting] -> FilePath -> IO ()
proof reports hints thy = do
got <- fmap (isabelleTheorems (takeFileName thy)) $ readFile thy
let want = nub $ hintTheorems hints
let unused = got \\ want
let missing = want \\ got
let reasons = map (\x -> (fst $ head x, map snd x)) $ groupBy ((==) `on` fst) $
sortBy (compare `on` fst) $ map (classifyMissing &&& id) missing
let summary = table $ let (*) = (,) in
["HLint hints" * want
,"HOL proofs" * got
,"Useful proofs" * (got `intersect` want)
,"Unused proofs" * unused
,"Unproved hints" * missing] ++
[(" " ++ name) * ps | (name,ps) <- reasons]
putStr $ unlines summary
forM_ reports $ \report -> do
let out = ("Unused proofs",unused) : map (first ("Unproved hints - " ++)) reasons
writeFile report $ unlines $ summary ++ "" : concat
[("== " ++ a ++ " ==") : "" : map show b | (a,b) <- out]
putStrLn $ "Report written to " ++ report
where
table xs = [a ++ replicate (n + 6 - length a - length bb) ' ' ++ bb | (a,b) <- xs, let bb = show $ length b]
where n = maximum $ map (length . fst) xs
missingFuncs = let a*b = [(b,a) | b <- words b] in concat
["IO" * "putChar putStr print putStrLn getLine getChar getContents hReady hPrint stdin"
,"Exit" * "exitSuccess"
,"Ord" * "(>) (<=) (>=) (<) compare minimum maximum sort sortBy"
,"Show" * "show shows showIntAtBase"
,"Read" * "reads read"
,"String" * "lines unlines words unwords"
,"Monad" * "mapM mapM_ sequence sequence_ msum mplus mzero liftM when unless return evaluate join void (>>=) (<=<) (>=>) forever ap"
,"Functor" * "fmap"
,"Numeric" * "(+) (*) fromInteger fromIntegral negate log (/) (-) (*) (^^) (^) subtract sqrt even odd"
,"Char" * "isControl isPrint isUpper isLower isAlpha isDigit"
,"Arrow" * "second first (***) (&&&)"
,"Applicative+" * "traverse for traverse_ for_ pure (<|>) (<**>)"
,"Exception" * "catch handle catchJust bracket error toException"
,"WeakPtr" * "mkWeak"
]
-- | Guess why a theorem is missing
classifyMissing :: Theorem -> String
classifyMissing Theorem{original = Just MatchExp{..}}
| _:_ <- [v :: Exp_ | v@Case{} <- universeBi (lhs,rhs)] = "case"
| _:_ <- [v :: Exp_ | v@ListComp{} <- universeBi (lhs,rhs)] = "list-comp"
| v:_ <- mapMaybe (`lookup` missingFuncs) [prettyPrint (v :: Name SrcSpanInfo) | v <- universeBi (lhs,rhs)] = v
classifyMissing _ = "?unknown"
-- Extract theorems out of Isabelle code (HLint.thy)
isabelleTheorems :: FilePath -> String -> [Theorem]
isabelleTheorems file = find . lexer 1
where
find ((i,"lemma"):(_,'\"':lemma):rest) = Theorem Nothing (file ++ ":" ++ show i) lemma : find rest
find ((i,"lemma"):(_,name):(_,":"):(_,'\"':lemma):rest) = Theorem Nothing (file ++ ":" ++ show i) lemma : find rest
find ((i,"lemma"):(_,"assumes"):(_,'\"':assumes):(_,"shows"):(_,'\"':lemma):rest) =
Theorem Nothing (file ++ ":" ++ show i) (assumes ++ " \\ " ++ lemma) : find rest
find ((i,"lemma"):rest) = Theorem Nothing (file ++ ":" ++ show i) "Unsupported lemma format" : find rest
find (x:xs) = find xs
find [] = []
lexer i x
| i `seq` False = []
| Just x <- stripPrefix "(*" x, (a,b) <- breaks "*)" x = lexer (add a i) b
| Just x <- stripPrefix "\"" x, (a,b) <- breaks "\"" x = (i,'\"':a) : lexer (add a i) b -- NOTE: drop the final "
| x:xs <- x, isSpace x = lexer (add [x] i) xs
| (a@(_:_),b) <- span (\y -> y == '_' || isAlpha y) x = (i,a) : lexer (add a i) b
lexer i (x:xs) = (i,[x]) : lexer (add [x] i) xs
lexer i [] = []
add s i = length (filter (== '\n') s) + i
breaks s x | Just x <- stripPrefix s x = ("",x)
breaks s (x:xs) = let (a,b) = breaks s xs in (x:a,b)
breaks s [] = ([],[])
reparen :: Setting -> Setting
reparen m@MatchExp{..} = m{lhs = f False lhs, rhs = f True rhs}
where f right x = if isLambda x || isIf x || badInfix x then Paren (ann x) x else x
badInfix (InfixApp _ _ op _) = prettyPrint op `elem` words "|| && ."
badInfix _ = False
reparen x = x
-- Extract theorems out of the hints
hintTheorems :: [Setting] -> [Theorem]
hintTheorems xs =
[ Theorem (Just m) (loc $ ann lhs) $ maybe "" assumes side ++ relationship notes a b
| m@MatchExp{..} <- map reparen xs, let a = exp1 $ typeclasses notes lhs, let b = exp1 rhs, a /= b]
where
loc (SrcSpanInfo (SrcSpan file ln _ _ _) _) = takeFileName file ++ ":" ++ show ln
subs xs = flip lookup [(reverse b, reverse a) | x <- words xs, let (a,'=':b) = break (== '=') $ reverse x]
funs = subs "id=ID not=neg or=the_or and=the_and (||)=tror (&&)=trand (++)=append (==)=eq (/=)=neq ($)=dollar"
ops = subs "||=orelse &&=andalso .=oo ===eq /==neq ++=++ !!=!! $=dollar $!=dollarBang"
pre = flip elem $ words "eq neq dollar dollarBang"
cons = subs "True=TT False=FF"
typeclasses notes x = foldr f x notes
where
f (ValidInstance cls var) x = evalState (transformM g x) True
where g v@Var{} | v ~= var = do
b <- get; put False
return $ if b then Paren an $ toNamed $ prettyPrint v ++ "::'a::" ++ cls ++ "_sym" else v
g v = return v :: State Bool Exp_
f _ x = x
relationship notes a b | any lazier notes = a ++ " \\ " ++ b
| DecreasesLaziness `elem` notes = b ++ " \\ " ++ a
| otherwise = a ++ " = " ++ b
where lazier IncreasesLaziness = True
lazier RemovesError{} = True
lazier _ = False
assumes (App _ op var)
| op ~= "isNat" = "le\\0\\" ++ prettyPrint var ++ " \\ FF \\ "
| op ~= "isNegZero" = "gt\\0\\" ++ prettyPrint var ++ " \\ FF \\ "
assumes (App _ op var) | op ~= "isWHNF" = prettyPrint var ++ " \\ \\ \\ "
assumes _ = ""
exp1 = exp . transformBi unqual
-- Syntax translations
exp (App _ a b) = exp a ++ "\\" ++ exp b
exp (Paren _ x) = "(" ++ exp x ++ ")"
exp (Var _ x) | Just x <- funs $ prettyPrint x = x
exp (Con _ (Special _ (TupleCon _ _ i))) = "\\" ++ replicate (i-1) ',' ++ "\\"
exp (Con _ x) | Just x <- cons $ prettyPrint x = x
exp (Tuple _ _ xs) = "\\" ++ intercalate ", " (map exp xs) ++ "\\"
exp (If _ a b c) = "If " ++ exp a ++ " then " ++ exp b ++ " else " ++ exp c
exp (Lambda _ xs y) = "\\ " ++ unwords (map pat xs) ++ ". " ++ exp y
exp (InfixApp _ x op y) | Just op <- ops $ prettyPrint op =
if pre op then op ++ "\\" ++ exp (paren x) ++ "\\" ++ exp (paren y) else exp x ++ " " ++ op ++ " " ++ exp y
-- Translations from the Haskell 2010 report
exp (InfixApp l a (QVarOp _ b) c) = exp $ App l (App l (Var l b) a) c -- S3.4
exp x@(LeftSection l e op) = let v = fresh x in exp $ Paren l $ Lambda l [toNamed v] $ InfixApp l e op (toNamed v) -- S3.5
exp x@(RightSection l op e) = let v = fresh x in exp $ Paren l $ Lambda l [toNamed v] $ InfixApp l (toNamed v) op e -- S3.5
exp x = prettyPrint x
pat (PTuple _ _ xs) = "\\" ++ intercalate ", " (map pat xs) ++ "\\"
pat x = prettyPrint x
fresh x = head $ ("z":["v" ++ show i | i <- [1..]]) \\ vars x
hlint-1.8.53/src/Parallel.hs 0000644 0000000 0000000 00000002247 12220306165 013775 0 ustar 00 0000000 0000000 {-
The parallel function (specialised to lists) is equivalent to:
import Control.Parallel.Strategies
parallel :: [IO [a]] -> IO [[a]]
parallel = return . withStrategy (parList $ seqList r0) . map unsafePerformIO
However, this version performs about 10% slower with 2 processors in GHC 6.12.1
-}
module Parallel(parallel) where
import System.IO.Unsafe
import GHC.Conc(numCapabilities)
import Control.Concurrent
import Control.Monad
parallel :: [IO a] -> IO [a]
parallel = if numCapabilities <= 1 then parallel1 else parallelN
parallel1 :: [IO a] -> IO [a]
parallel1 [] = return []
parallel1 (x:xs) = do
x2 <- x
xs2 <- unsafeInterleaveIO $ parallel1 xs
return $ x2:xs2
parallelN :: [IO a] -> IO [a]
parallelN xs = do
ms <- mapM (const newEmptyMVar) xs
chan <- newChan
mapM_ (writeChan chan . Just) $ zip ms xs
replicateM_ numCapabilities (writeChan chan Nothing >> forkIO (f chan))
parallel1 $ map takeMVar ms
where
f chan = do
v <- readChan chan
case v of
Nothing -> return ()
Just (m,x) -> do
x' <- x
putMVar m x'
f chan
hlint-1.8.53/src/Main.hs 0000644 0000000 0000000 00000000367 12220306165 013126 0 ustar 00 0000000 0000000
module Main where
import Language.Haskell.HLint
import Control.Monad
import System.Environment
import System.Exit
main :: IO ()
main = do
args <- getArgs
errs <- hlint args
when (length errs > 0) $
exitWith $ ExitFailure 1
hlint-1.8.53/src/Idea.hs 0000644 0000000 0000000 00000002700 12220306165 013075 0 ustar 00 0000000 0000000 {-# LANGUAGE RecordWildCards, NoMonomorphismRestriction #-}
module Idea(module Idea, Note(..), showNotes, Severity(..)) where
import HSE.All
import Settings
import Language.Haskell.HsColour.TTY
import Language.Haskell.HsColour.Colourise
import Util
data Idea
= Idea {func :: FuncName, severity :: Severity, hint :: String, loc :: SrcLoc, from :: String, to :: String, note :: [Note]}
| ParseError {severity :: Severity, hint :: String, loc :: SrcLoc, msg :: String, from :: String}
deriving (Eq,Ord)
isParseError ParseError{} = True; isParseError _ = False
instance Show Idea where
show = showEx id
showANSI :: IO (Idea -> String)
showANSI = do
prefs <- readColourPrefs
return $ showEx (hscolour prefs)
showEx :: (String -> String) -> Idea -> String
showEx tt Idea{..} = unlines $
[showSrcLoc loc ++ ": " ++ show severity ++ ": " ++ hint] ++
f "Found" from ++ f "Why not" to ++
["Note: " ++ n | let n = showNotes note, n /= ""]
where
f msg x | null xs = [msg ++ " remove it."]
| otherwise = (msg ++ ":") : map (" "++) xs
where xs = lines $ tt x
showEx tt ParseError{..} = unlines $
[showSrcLoc loc ++ ": Parse error","Error message:"," " ++ msg,"Code:"] ++ map (" "++) (lines $ tt from)
rawIdea = Idea ("","")
idea severity hint from to = rawIdea severity hint (toSrcLoc $ ann from) (f from) (f to) []
where f = ltrim . prettyPrint
warn = idea Warning
err = idea Error
hlint-1.8.53/src/HLint.hs 0000644 0000000 0000000 00000006737 12220306165 013267 0 ustar 00 0000000 0000000 {-# LANGUAGE RecordWildCards #-}
module HLint(hlint, Suggestion, suggestionLocation, suggestionSeverity, Severity(..)) where
import Control.Monad
import Data.List
import Data.Maybe
import System.Exit
import CmdLine
import Settings
import Report
import Idea
import Apply
import Test
import Proof
import Util
import Parallel
import HSE.All
-- | A suggestion - the @Show@ instance is of particular use.
newtype Suggestion = Suggestion {fromSuggestion :: Idea}
deriving (Eq,Ord)
instance Show Suggestion where
show = show . fromSuggestion
-- | From a suggestion, extract the file location it refers to.
suggestionLocation :: Suggestion -> SrcLoc
suggestionLocation = loc . fromSuggestion
-- | From a suggestion, determine how severe it is.
suggestionSeverity :: Suggestion -> Severity
suggestionSeverity = severity . fromSuggestion
-- | This function takes a list of command line arguments, and returns the given suggestions.
-- To see a list of arguments type @hlint --help@ at the console.
-- This function writes to the stdout/stderr streams, unless @--quiet@ is specified.
--
-- As an example:
--
-- > do hints <- hlint ["src", "--ignore=Use map","--quiet"]
-- > when (length hints > 3) $ error "Too many hints!"
hlint :: [String] -> IO [Suggestion]
hlint args = do
cmd@Cmd{..} <- getCmd args
let flags = parseFlags{cppFlags=cmdCpp, encoding=cmdEncoding, language=cmdLanguage}
if cmdTest then do
failed <- test (\x -> hlint x >> return ()) cmdDataDir cmdGivenHints
when (failed > 0) exitFailure
return []
else if notNull cmdProof then do
s <- readAllSettings cmd flags
let reps = if cmdReports == ["report.html"] then ["report.txt"] else cmdReports
mapM_ (proof reps s) cmdProof
return []
else if isNothing cmdFiles && notNull cmdFindHints then
mapM_ (\x -> putStrLn . fst =<< findSettings flags x) cmdFindHints >> return []
else if isNothing cmdFiles then
exitWithHelp
else if cmdFiles == Just [] then
error "No files found"
else
runHints cmd flags
readAllSettings :: Cmd -> ParseFlags -> IO [Setting]
readAllSettings Cmd{..} flags = do
settings1 <- readSettings cmdDataDir cmdHintFiles cmdWithHints
settings2 <- concatMapM (fmap snd . findSettings flags) cmdFindHints
settings3 <- return [Classify Ignore x ("","") | x <- cmdIgnore]
return $ settings1 ++ settings2 ++ settings3
runHints :: Cmd -> ParseFlags -> IO [Suggestion]
runHints cmd@Cmd{..} flags = do
let outStrLn x = unless cmdQuiet $ putStrLn x
settings <- readAllSettings cmd flags
let files = fromMaybe [] cmdFiles
ideas <- if cmdCross
then applyHintFiles flags settings files
else fmap concat $ parallel [listM' =<< applyHintFile flags settings x | x <- files]
let (showideas,hideideas) = partition (\i -> cmdShowAll || severity i /= Ignore) ideas
showItem <- if cmdColor then showANSI else return show
mapM_ (outStrLn . showItem) showideas
if null showideas then
when (cmdReports /= []) $ outStrLn "Skipping writing reports"
else
forM_ cmdReports $ \x -> do
outStrLn $ "Writing report to " ++ x ++ " ..."
writeReport cmdDataDir x showideas
outStrLn $
(let i = length showideas in if i == 0 then "No suggestions" else show i ++ " suggestion" ++ ['s'|i/=1]) ++
(let i = length hideideas in if i == 0 then "" else " (" ++ show i ++ " ignored)")
return $ map Suggestion showideas
hlint-1.8.53/src/CmdLine.hs 0000644 0000000 0000000 00000021426 12220306165 013554 0 ustar 00 0000000 0000000 {-# LANGUAGE PatternGuards #-}
module CmdLine(Cmd(..), CppFlags(..), getCmd, exitWithHelp) where
import Control.Monad
import Data.Char
import Data.List
import Data.Maybe
import System.Console.GetOpt
import System.Directory
import System.Exit
import System.FilePath
import Language.Preprocessor.Cpphs
import Language.Haskell.Exts.Extension
import Util
import Paths_hlint
import Data.Version
data CppFlags
= NoCpp
| CppSimple
| Cpphs CpphsOptions
-- FIXME: Hints vs GivenHints is horrible
data Cmd = Cmd
{cmdTest :: Bool -- ^ run in test mode?
,cmdFiles :: Maybe [FilePath] -- ^ which files to run it on, nothing = none given
,cmdHintFiles :: [FilePath] -- ^ which settingsfiles to use
,cmdGivenHints :: [FilePath] -- ^ which settignsfiles were explicitly given
,cmdWithHints :: [String] -- ^ hints that are given on the command line
,cmdReports :: [FilePath] -- ^ where to generate reports
,cmdIgnore :: [String] -- ^ the hints to ignore
,cmdShowAll :: Bool -- ^ display all skipped items
,cmdColor :: Bool -- ^ color the result
,cmdCpp :: CppFlags -- ^ options for CPP
,cmdDataDir :: FilePath -- ^ the data directory
,cmdEncoding :: Encoding -- ^ the text encoding
,cmdFindHints :: [FilePath] -- ^ source files to look for hints in
,cmdLanguage :: [Extension] -- ^ the extensions (may be prefixed by "No")
,cmdQuiet :: Bool -- ^ supress all console output
,cmdCross :: Bool -- ^ work between source files, applies to hints such as duplicate code between modules
,cmdProof :: [FilePath] -- ^ a proof script to check against
}
data Opts = Help
| Ver
| Test
| Hints FilePath
| WithHint String
| Path FilePath
| Report FilePath
| Skip String
| ShowAll
| Color
| Define String
| Include String
| SimpleCpp
| Ext String
| DataDir String
| Encoding String
| FindHints FilePath
| Language String
| Proof FilePath
| Quiet
| Cross
| Ansi
deriving Eq
opts = [Option "?" ["help"] (NoArg Help) "Display help message"
,Option "v" ["version"] (NoArg Ver) "Display version information"
,Option "r" ["report"] (OptArg (Report . fromMaybe "report.html") "file") "Generate a report in HTML"
,Option "h" ["hint"] (ReqArg Hints "file") "Hint/ignore file to use"
,Option "w" ["with"] (ReqArg WithHint "hint") "Extra hints to use"
,Option "c" ["color","colour"] (NoArg Color) "Color output (requires ANSI terminal)"
,Option "i" ["ignore"] (ReqArg Skip "hint") "Ignore a particular hint"
,Option "s" ["show"] (NoArg ShowAll) "Show all ignored ideas"
,Option "e" ["extension"] (ReqArg Ext "ext") "File extensions to search (defaults to hs and lhs)"
,Option "X" ["language"] (ReqArg Language "lang") "Language extensions (Arrows, NoCPP)"
,Option "u" ["utf8"] (NoArg $ Encoding "UTF-8") "Use UTF-8 text encoding"
,Option "" ["encoding"] (ReqArg Encoding "encoding") "Choose the text encoding"
,Option "x" ["cross"] (NoArg Cross) "Work between modules"
,Option "f" ["find"] (ReqArg FindHints "file") "Find hints in a Haskell file"
,Option "t" ["test"] (NoArg Test) "Run in test mode"
,Option "d" ["datadir"] (ReqArg DataDir "dir") "Override the data directory"
,Option "p" ["path"] (ReqArg Path "dir") "Directory in which to search for files"
,Option "q" ["quiet"] (NoArg Quiet) "Supress most console output"
,Option "" ["proof"] (ReqArg Proof "file") "Isabelle/HOLCF theory file"
,Option "" ["cpp-define"] (ReqArg Define "name[=value]") "CPP #define"
,Option "" ["cpp-include"] (ReqArg Include "dir") "CPP include path"
,Option "" ["cpp-simple"] (NoArg SimpleCpp) "Use a simple CPP (strip # lines)"
,Option "" ["cpp-ansi"] (NoArg Ansi) "Use CPP in ANSI compatibility mode"
]
-- | Exit out if you need to display help info
getCmd :: [String] -> IO Cmd
getCmd args = do
let (opt,files,err) = getOpt Permute opts args
unless (null err) $
error $ unlines $ "Unrecognised arguments:" : err
when (Ver `elem` opt) $ do
putStr versionText
exitSuccess
when (Help `elem` opt) exitWithHelp
let test = Test `elem` opt
dataDir <- last $ getDataDir : [return x | DataDir x <- opt]
let exts = [x | Ext x <- opt]
exts2 = if null exts then ["hs","lhs"] else exts
let path = [x | Path x <- opt] ++ ["."]
files <- if null files then return Nothing else fmap Just $ concatMapM (getFile path exts2) files
findHints <- concatMapM (getFile path exts2) [x | FindHints x <- opt]
let hintFiles = [x | Hints x <- opt]
let withHints = [x | WithHint x <- opt]
hints <- mapM (getHintFile dataDir) $ hintFiles ++ ["HLint" | null hintFiles && null withHints]
let givenHints = if null hintFiles then [] else hints
let languages = getExtensions [x | Language x <- opt]
let cpphs = defaultCpphsOptions
{boolopts=defaultBoolOptions{hashline=False, ansi=Ansi `elem` opt}
,includes = [x | Include x <- opt]
,defines = [(a,drop 1 b) | Define x <- opt, let (a,b) = break (== '=') x]
}
let cpp | SimpleCpp `elem` opt = CppSimple -- must be first, so can disable CPP
| EnableExtension CPP `elem` languages = Cpphs cpphs
| otherwise = NoCpp
encoding <- newEncoding $ last $ "" : [x | Encoding x <- opt]
return Cmd
{cmdTest = test
,cmdFiles = files
,cmdHintFiles = hints
,cmdGivenHints = givenHints
,cmdWithHints = withHints
,cmdReports = [x | Report x <- opt]
,cmdIgnore = [x | Skip x <- opt]
,cmdShowAll = ShowAll `elem` opt
,cmdColor = Color `elem` opt
,cmdCpp = cpp
,cmdDataDir = dataDir
,cmdEncoding = encoding
,cmdFindHints = findHints
,cmdLanguage = languages
,cmdQuiet = Quiet `elem` opt
,cmdCross = Cross `elem` opt
,cmdProof = [x | Proof x <- opt]
}
exitWithHelp :: IO a
exitWithHelp = do
putStr helpText
exitSuccess
versionText :: String
versionText = "HLint v" ++ showVersion version ++ ", (C) Neil Mitchell 2006-2013\n"
helpText :: String
helpText = unlines
[versionText
," hlint [files/directories] [options]"
,usageInfo "" opts
,"HLint gives hints on how to improve Haskell code."
,""
,"To check all Haskell files in 'src' and generate a report type:"
," hlint src --report"
]
"." <\> x = x
x <\> y = x > y
getFile :: [FilePath] -> [String] -> FilePath -> IO [FilePath]
getFile path _ "-" = return ["-"]
getFile [] exts file = error $ "Couldn't find file: " ++ file
getFile (p:ath) exts file = do
isDir <- doesDirectoryExist $ p <\> file
if isDir then do
xs <- getDirectoryContentsRecursive $ p <\> file
return [x | x <- xs, drop 1 (takeExtension x) `elem` exts]
else do
isFil <- doesFileExist $ p <\> file
if isFil then return [p <\> file]
else do
res <- getModule p exts file
case res of
Just x -> return [x]
Nothing -> getFile ath exts file
getModule :: FilePath -> [String] -> FilePath -> IO (Maybe FilePath)
getModule path exts x | not (any isSpace x) && all isMod xs = f exts
where
xs = words $ map (\x -> if x == '.' then ' ' else x) x
isMod (x:xs) = isUpper x && all (\x -> isAlphaNum x || x == '_') xs
isMod _ = False
pre = path <\> joinPath xs
f [] = return Nothing
f (x:xs) = do
let s = pre <.> x
b <- doesFileExist s
if b then return $ Just s else f xs
getModule _ _ _ = return Nothing
getHintFile :: FilePath -> FilePath -> IO FilePath
getHintFile _ "-" = return "-"
getHintFile dataDir x = do
let poss = nub $ concat [x : [x <.> "hs" | takeExtension x /= ".hs"] | x <- [x,dataDir > x]]
f poss poss
where
f o [] = error $ unlines $ [
"Couldn't find file: " ++ x,
"Tried with:"] ++ map (" "++) o
f o (x:xs) = do
b <- doesFileExist x
if b then return x else f o xs
getExtensions :: [String] -> [Extension]
getExtensions = foldl f defaultExtensions
where
f a "Haskell98" = []
f a ('N':'o':x) | Just x <- readExtension x = delete x a
f a x | Just x <- readExtension x = x : delete x a
f a x = error $ "Unknown extension: " ++ x
readExtension :: String -> Maybe Extension
readExtension x = case classifyExtension x of
UnknownExtension _ -> Nothing
x -> Just x
hlint-1.8.53/src/Apply.hs 0000644 0000000 0000000 00000010250 12220306165 013317 0 ustar 00 0000000 0000000
module Apply(applyHintFile, applyHintFiles, applyHintString) where
import HSE.All
import Hint.All
import Control.Arrow
import Data.Char
import Data.List
import Data.Maybe
import Data.Ord
import Settings
import Idea
import Util
-- | Apply hints to a single file.
applyHintFile :: ParseFlags -> [Setting] -> FilePath -> IO [Idea]
applyHintFile flags s file = do
res <- parseModuleFile flags s file
return $ case res of
Left err -> [err]
Right m -> executeHints s [m]
-- | Apply hints to the contents of a single file.
applyHintString :: ParseFlags -> [Setting] -> FilePath -> String -> IO [Idea]
applyHintString flags s file src = do
res <- parseModuleString flags s file src
return $ case res of
Left err -> [err]
Right m -> executeHints s [m]
-- | Apply hints to multiple files, allowing cross-file hints to fire.
applyHintFiles :: ParseFlags -> [Setting] -> [FilePath] -> IO [Idea]
applyHintFiles flags s files = do
(err, ms) <- fmap unzipEither $ mapM (parseModuleFile flags s) files
return $ err ++ executeHints s ms
-- | Given a list of settings (a way to classify) and a list of hints, run them over a list of modules.
executeHints :: [Setting] -> [Module_] -> [Idea]
executeHints s ms = concat $
[ map (classify $ s ++ mapMaybe readPragma (moduleDecls m)) $
order "" [i | ModuHint h <- hints, i <- h nm m] ++
concat [order (fromNamed d) [i | h <- decHints, i <- h d] | d <- moduleDecls m]
| (nm,m) <- mns
, let decHints = [h nm m | DeclHint h <- hints] -- partially apply
, let order n = map (\i -> i{func = (moduleName m,n)}) . sortBy (comparing loc)] ++
[map (classify s) $ op mns | CrossHint op <- hints]
where
mns = map (moduleScope &&& id) ms
hints = for (allHints s) $ \x -> case x of
CrossHint op | length ms <= 1 -> ModuHint $ \a b -> op [(a,b)]
_ -> x
-- | Like 'parseModuleString', but also load the file from disk.
parseModuleFile :: ParseFlags -> [Setting] -> FilePath -> IO (Either Idea Module_)
parseModuleFile flags s file = do
src <- readFileEncoding (encoding flags) file
parseModuleString flags s file src
-- | Return either an idea (a parse error) or the module. In IO because might call the C pre processor.
parseModuleString :: ParseFlags -> [Setting] -> FilePath -> String -> IO (Either Idea Module_)
parseModuleString flags s file src = do
res <- parseString flags{infixes=[x | Infix x <- s]} file src
case snd res of
ParseOk m -> return $ Right m
ParseFailed sl msg | length src `seq` True -> do
-- figure out the best line number to grab context from, by reparsing
(str2,pr2) <- parseString (parseFlagsNoLocations flags) "" src
let ctxt = case pr2 of
ParseFailed sl2 _ -> context (srcLine sl2) str2
_ -> context (srcLine sl) src
return $ Left $ classify s $ ParseError Warning "Parse error" sl msg ctxt
-- | Given a line number, and some source code, put bird ticks around the appropriate bit.
context :: Int -> String -> String
context lineNo src =
unlines $ trimBy (all isSpace) $
zipWith (++) ticks $ take 5 $ drop (lineNo - 3) $ lines src ++ [""]
where ticks = [" "," ","> "," "," "]
-- | Find which hints a list of settings implies.
allHints :: [Setting] -> [Hint]
allHints xs = dynamicHints xs : map f builtin
where builtin = nub $ concat [if x == "All" then map fst staticHints else [x] | Builtin x <- xs]
f x = fromMaybe (error $ "Unknown builtin hints: HLint.Builtin." ++ x) $ lookup x staticHints
-- | Given some settings, make sure the severity field of the Idea is correct.
classify :: [Setting] -> Idea -> Idea
classify xs i = i{severity = foldl' (f i) (severity i) $ filter isClassify xs}
where
-- figure out if we need to change the severity
f :: Idea -> Severity -> Setting -> Severity
f i r c | matchHint (hintS c) (hint i) && matchFunc (funcS c) (func_ i) = severityS c
| otherwise = r
func_ x = if isParseError x then ("","") else func x
matchHint = (~=)
matchFunc (x1,x2) (y1,y2) = (x1~=y1) && (x2~=y2)
x ~= y = null x || x == y
hlint-1.8.53/src/Language/ 0000755 0000000 0000000 00000000000 12220306165 013423 5 ustar 00 0000000 0000000 hlint-1.8.53/src/Language/Haskell/ 0000755 0000000 0000000 00000000000 12220306165 015006 5 ustar 00 0000000 0000000 hlint-1.8.53/src/Language/Haskell/HLint.hs 0000644 0000000 0000000 00000000340 12220306165 016355 0 ustar 00 0000000 0000000 {-|
This module provides a library interface to HLint. The current
interface is strongly modelled on the command line interface,
and is expected to evolve.
-}
module Language.Haskell.HLint(module HLint) where
import HLint
hlint-1.8.53/src/HSE/ 0000755 0000000 0000000 00000000000 12220306165 012317 5 ustar 00 0000000 0000000 hlint-1.8.53/src/HSE/Util.hs 0000644 0000000 0000000 00000021633 12220306165 013575 0 ustar 00 0000000 0000000 {-# LANGUAGE FlexibleContexts #-}
module HSE.Util where
import Control.Monad
import Data.List
import Data.Maybe
import System.FilePath
import HSE.Type
import Language.Haskell.Exts.Annotated.Simplify(sQName, sAssoc)
---------------------------------------------------------------------
-- ACCESSOR/TESTER
opExp :: QOp S -> Exp_
opExp (QVarOp s op) = Var s op
opExp (QConOp s op) = Con s op
expOp :: Exp_ -> Maybe (QOp S)
expOp (Var s op) = Just $ QVarOp s op
expOp (Con s op) = Just $ QConOp s op
expOp _ = Nothing
moduleDecls :: Module_ -> [Decl_]
moduleDecls (Module _ _ _ _ xs) = xs
moduleName :: Module_ -> String
moduleName (Module _ Nothing _ _ _) = "Main"
moduleName (Module _ (Just (ModuleHead _ (ModuleName _ x) _ _)) _ _ _) = x
moduleImports :: Module_ -> [ImportDecl S]
moduleImports (Module _ _ _ x _) = x
modulePragmas :: Module_ -> [ModulePragma S]
modulePragmas (Module _ _ x _ _) = x
fromModuleName :: ModuleName S -> String
fromModuleName (ModuleName _ x) = x
isChar :: Exp_ -> Bool
isChar (Lit _ Char{}) = True
isChar _ = False
fromChar :: Exp_ -> Char
fromChar (Lit _ (Char _ x _)) = x
isString :: Exp_ -> Bool
isString (Lit _ String{}) = True
isString _ = False
fromString :: Exp_ -> String
fromString (Lit _ (String _ x _)) = x
isPString (PLit _ String{}) = True; isPString _ = False
fromPString (PLit _ (String _ x _)) = x
fromParen :: Exp_ -> Exp_
fromParen (Paren _ x) = fromParen x
fromParen x = x
fromPParen :: Pat s -> Pat s
fromPParen (PParen _ x) = fromPParen x
fromPParen x = x
fromTyParen :: Type s -> Type s
fromTyParen (TyParen _ x) = fromTyParen x
fromTyParen x = x
fromDeriving :: Deriving s -> [InstHead s]
fromDeriving (Deriving _ x) = x
-- is* :: Exp_ -> Bool
-- is* :: Decl_ -> Bool
isVar Var{} = True; isVar _ = False
isCon Con{} = True; isCon _ = False
isApp App{} = True; isApp _ = False
isInfixApp InfixApp{} = True; isInfixApp _ = False
isList List{} = True; isList _ = False
isAnyApp x = isApp x || isInfixApp x
isParen Paren{} = True; isParen _ = False
isIf If{} = True; isIf _ = False
isLambda Lambda{} = True; isLambda _ = False
isMDo MDo{} = True; isMDo _ = False
isBoxed Boxed{} = True; isBoxed _ = False
isDerivDecl DerivDecl{} = True; isDerivDecl _ = False
isPBangPat PBangPat{} = True; isPBangPat _ = False
isPExplTypeArg PExplTypeArg{} = True; isPExplTypeArg _ = False
isPFieldPun PFieldPun{} = True; isPFieldPun _ = False
isFieldPun FieldPun{} = True; isFieldPun _ = False
isPWildCard PWildCard{} = True; isPWildCard _ = False
isPFieldWildcard PFieldWildcard{} = True; isPFieldWildcard _ = False
isFieldWildcard FieldWildcard{} = True; isFieldWildcard _ = False
isPViewPat PViewPat{} = True; isPViewPat _ = False
isParComp ParComp{} = True; isParComp _ = False
isPatTypeSig PatTypeSig{} = True; isPatTypeSig _ = False
isQuasiQuote QuasiQuote{} = True; isQuasiQuote _ = False
isSpliceDecl SpliceDecl{} = True; isSpliceDecl _ = False
isNewType NewType{} = True; isNewType _ = False
isSection LeftSection{} = True
isSection RightSection{} = True
isSection _ = False
allowRightSection x = x `notElem` ["-","#"]
allowLeftSection x = x /= "#"
unqual :: QName S -> QName S
unqual (Qual an _ x) = UnQual an x
unqual x = x
fromQual :: QName S -> Name S
fromQual (Qual _ _ x) = x
fromQual (UnQual _ x) = x
isSpecial :: QName S -> Bool
isSpecial Special{} = True; isSpecial _ = False
isDol :: QOp S -> Bool
isDol (QVarOp _ (UnQual _ (Symbol _ "$"))) = True
isDol _ = False
isDot :: QOp S -> Bool
isDot (QVarOp _ (UnQual _ (Symbol _ "."))) = True
isDot _ = False
isDotApp :: Exp_ -> Bool
isDotApp (InfixApp _ _ dot _) | isDot dot = True
isDotApp _ = False
dotApp :: Exp_ -> Exp_ -> Exp_
dotApp x = InfixApp an x (QVarOp an $ UnQual an $ Symbol an ".")
dotApps :: [Exp_] -> Exp_
dotApps [x] = x
dotApps (x:xs) = dotApp x (dotApps xs)
isLexeme Var{} = True
isLexeme Con{} = True
isLexeme Lit{} = True
isLexeme _ = False
isWHNF :: Exp_ -> Bool
isWHNF Con{} = True
isWHNF Lit{} = True
isWHNF Lambda{} = True
isWHNF Tuple{} = True
isWHNF List{} = True
isWHNF (Paren _ x) = isWHNF x
isWHNF RecConstr{} = True
isWHNF (ExpTypeSig _ x _) = isWHNF x
isWHNF _ = False
---------------------------------------------------------------------
-- HSE FUNCTIONS
getEquations :: Decl s -> [Decl s]
getEquations (FunBind s xs) = map (FunBind s . (:[])) xs
getEquations x@PatBind{} = [toFunBind x]
getEquations x = [x]
toFunBind :: Decl s -> Decl s
toFunBind (PatBind s (PVar _ name) _ bod bind) = FunBind s [Match s name [] bod bind]
toFunBind x = x
fromGuardedAlts :: GuardedAlts s -> Rhs s
fromGuardedAlts (UnGuardedAlt s x) = UnGuardedRhs s x
fromGuardedAlts (GuardedAlts s xs) = GuardedRhss s [GuardedRhs a b c | GuardedAlt a b c <- xs]
toGuardedAlts :: Rhs s -> GuardedAlts s
toGuardedAlts (UnGuardedRhs s x) = UnGuardedAlt s x
toGuardedAlts (GuardedRhss s xs) = GuardedAlts s [GuardedAlt a b c | GuardedRhs a b c <- xs]
-- case and if both have branches, nothing else does
replaceBranches :: Exp s -> ([Exp s], [Exp s] -> Exp s)
replaceBranches (If s a b c) = ([b,c], \[b,c] -> If s a b c)
replaceBranches (Case s a bs) = (concatMap f bs, Case s a . g bs)
where
f (Alt _ _ (UnGuardedAlt _ x) _) = [x]
f (Alt _ _ (GuardedAlts _ xs) _) = [x | GuardedAlt _ _ x <- xs]
g (Alt s1 a (UnGuardedAlt s2 _) b:rest) (x:xs) = Alt s1 a (UnGuardedAlt s2 x) b : g rest xs
g (Alt s1 a (GuardedAlts s2 ns) b:rest) xs =
Alt s1 a (GuardedAlts s2 [GuardedAlt a b x | (GuardedAlt a b _,x) <- zip ns as]) b : g rest bs
where (as,bs) = splitAt (length ns) xs
g [] [] = []
replaceBranches x = ([], \[] -> x)
---------------------------------------------------------------------
-- VECTOR APPLICATION
apps :: [Exp_] -> Exp_
apps = foldl1 (App an)
fromApps :: Exp_ -> [Exp_]
fromApps (App _ x y) = fromApps x ++ [y]
fromApps x = [x]
-- Rule for the Uniplate Apps functions
-- Given (f a) b, consider the children to be: children f ++ [a,b]
childrenApps :: Exp_ -> [Exp_]
childrenApps (App _ x@App{} y) = childrenApps x ++ [y]
childrenApps (App _ x y) = children x ++ [y]
childrenApps x = children x
descendApps :: (Exp_ -> Exp_) -> Exp_ -> Exp_
descendApps f (App s x@App{} y) = App s (descendApps f x) (f y)
descendApps f (App s x y) = App s (descend f x) (f y)
descendApps f x = descend f x
descendAppsM :: Monad m => (Exp_ -> m Exp_) -> Exp_ -> m Exp_
descendAppsM f (App s x@App{} y) = liftM2 (App s) (descendAppsM f x) (f y)
descendAppsM f (App s x y) = liftM2 (App s) (descendM f x) (f y)
descendAppsM f x = descendM f x
universeApps :: Exp_ -> [Exp_]
universeApps x = x : concatMap universeApps (childrenApps x)
transformApps :: (Exp_ -> Exp_) -> Exp_ -> Exp_
transformApps f = f . descendApps (transformApps f)
transformAppsM :: (Monad m) => (Exp_ -> m Exp_) -> Exp_ -> m Exp_
transformAppsM f x = f =<< descendAppsM (transformAppsM f) x
---------------------------------------------------------------------
-- UNIPLATE FUNCTIONS
universeS :: Biplate x (f S) => x -> [f S]
universeS = universeBi
childrenS :: Biplate x (f S) => x -> [f S]
childrenS = childrenBi
-- return the parent along with the child
universeParentExp :: Biplate a Exp_ => a -> [(Maybe (Int, Exp_), Exp_)]
universeParentExp xs = concat [(Nothing, x) : f x | x <- childrenBi xs]
where f p = concat [(Just (i,p), c) : f c | (i,c) <- zip [0..] $ children p]
---------------------------------------------------------------------
-- SRCLOC FUNCTIONS
showSrcLoc :: SrcLoc -> String
showSrcLoc (SrcLoc file line col) = take 1 file ++ f (drop 1 file) ++ ":" ++ show line ++ ":" ++ show col
where f (x:y:zs) | isPathSeparator x && isPathSeparator y = f $ x:zs
f (x:xs) = x : f xs
f [] = []
toSrcLoc :: SrcInfo si => si -> SrcLoc
toSrcLoc = getPointLoc
nullSrcLoc :: SrcLoc
nullSrcLoc = SrcLoc "" 0 0
an :: SrcSpanInfo
an = toSrcInfo nullSrcLoc [] nullSrcLoc
dropAnn :: Functor f => f s -> f ()
dropAnn = fmap (const ())
---------------------------------------------------------------------
-- SRCLOC EQUALITY
-- enforce all being on S, as otherwise easy to =~= on a Just, and get the wrong functor
x /=~= y = not $ x =~= y
elem_, notElem_ :: (Annotated f, Eq (f ())) => f S -> [f S] -> Bool
elem_ x = any (x =~=)
notElem_ x = not . elem_ x
nub_ :: (Annotated f, Eq (f ())) => [f S] -> [f S]
nub_ = nubBy (=~=)
intersect_ :: (Annotated f, Eq (f ())) => [f S] -> [f S] -> [f S]
intersect_ = intersectBy (=~=)
eqList, neqList :: (Annotated f, Eq (f ())) => [f S] -> [f S] -> Bool
neqList x y = not $ eqList x y
eqList (x:xs) (y:ys) = x =~= y && eqList xs ys
eqList [] [] = True
eqList _ _ = False
eqMaybe:: (Annotated f, Eq (f ())) => Maybe (f S) -> Maybe (f S) -> Bool
eqMaybe (Just x) (Just y) = x =~= y
eqMaybe Nothing Nothing = True
eqMaybe _ _ = False
---------------------------------------------------------------------
-- FIXITIES
getFixity :: Decl a -> [Fixity]
getFixity (InfixDecl sl a mp ops) = [Fixity (sAssoc a) (fromMaybe 9 mp) (sQName $ UnQual sl $ f op) | op <- ops]
where f (VarOp _ x) = x
f (ConOp _ x) = x
getFixity _ = []
hlint-1.8.53/src/HSE/Type.hs 0000644 0000000 0000000 00000111076 12220306165 013602 0 ustar 00 0000000 0000000
module HSE.Type(module HSE.Type, module Export) where
-- Almost all from the Annotated module, but the fixity resolution from Annotated
-- uses the unannotated Assoc enumeration, so export that instead
import Language.Haskell.Exts.Annotated as Export hiding (parse, loc, parseFile, paren, Assoc(..))
import Language.Haskell.Exts as Export(Assoc(..))
import Data.Generics.Uniplate.Data as Export
type S = SrcSpanInfo
type Module_ = Module S
type Decl_ = Decl S
type Exp_ = Exp S
type Pat_ = Pat S
type Type_ = Type S
{-!
deriving instance UniplateDirect (Pat S) (Pat S)
deriving instance UniplateDirect (Exp S)
deriving instance UniplateDirect (Pat S)
deriving instance UniplateDirect (Pat S) (Exp S)
deriving instance UniplateDirect (Binds S) (Exp S)
deriving instance UniplateDirect (Alt S) (Exp S)
deriving instance UniplateDirect (Stmt S) (Exp S)
deriving instance UniplateDirect (QualStmt S) (Exp S)
deriving instance UniplateDirect [QualStmt S] (Exp S)
deriving instance UniplateDirect (Bracket S) (Exp S)
deriving instance UniplateDirect (Splice S) (Exp S)
deriving instance UniplateDirect (XAttr S) (Exp S)
deriving instance UniplateDirect (Maybe (Exp S)) (Exp S)
deriving instance UniplateDirect (FieldUpdate S) (Exp S)
deriving instance UniplateDirect (PatField S) (Pat S)
deriving instance UniplateDirect (Exp S) (Pat S)
deriving instance UniplateDirect (RPat S) (Pat S)
deriving instance UniplateDirect (PXAttr S) (Pat S)
deriving instance UniplateDirect (Maybe (Pat S)) (Pat S)
deriving instance UniplateDirect (PatField S) (Exp S)
deriving instance UniplateDirect (RPat S) (Exp S)
deriving instance UniplateDirect (PXAttr S) (Exp S)
deriving instance UniplateDirect (Maybe (Pat S)) (Exp S)
deriving instance UniplateDirect (Decl S) (Exp S)
deriving instance UniplateDirect (IPBind S) (Exp S)
deriving instance UniplateDirect (GuardedAlts S) (Exp S)
deriving instance UniplateDirect (Maybe (Binds S)) (Exp S)
deriving instance UniplateDirect (Maybe (Exp S)) (Exp S)
deriving instance UniplateDirect (FieldUpdate S) (Exp S)
deriving instance UniplateDirect (PatField S) (Pat S)
deriving instance UniplateDirect (Exp S) (Pat S)
deriving instance UniplateDirect (RPat S) (Pat S)
deriving instance UniplateDirect (PXAttr S) (Pat S)
deriving instance UniplateDirect (Maybe (Pat S)) (Pat S)
deriving instance UniplateDirect (PatField S) (Exp S)
deriving instance UniplateDirect (RPat S) (Exp S)
deriving instance UniplateDirect (PXAttr S) (Exp S)
deriving instance UniplateDirect (Maybe (Pat S)) (Exp S)
deriving instance UniplateDirect (Decl S) (Exp S)
deriving instance UniplateDirect (IPBind S) (Exp S)
deriving instance UniplateDirect (GuardedAlts S) (Exp S)
deriving instance UniplateDirect (Maybe (Binds S)) (Exp S)
deriving instance UniplateDirect (Binds S) (Pat S)
deriving instance UniplateDirect (Alt S) (Pat S)
deriving instance UniplateDirect (Stmt S) (Pat S)
deriving instance UniplateDirect (Maybe (Exp S)) (Pat S)
deriving instance UniplateDirect (FieldUpdate S) (Pat S)
deriving instance UniplateDirect (QualStmt S) (Pat S)
deriving instance UniplateDirect [QualStmt S] (Pat S)
deriving instance UniplateDirect (Bracket S) (Pat S)
deriving instance UniplateDirect (Splice S) (Pat S)
deriving instance UniplateDirect (XAttr S) (Pat S)
deriving instance UniplateDirect (Maybe [ClassDecl S]) (Exp S)
deriving instance UniplateDirect (Maybe [InstDecl S]) (Exp S)
deriving instance UniplateDirect (Match S) (Exp S)
deriving instance UniplateDirect (Rhs S) (Exp S)
deriving instance UniplateDirect (Rule S) (Exp S)
deriving instance UniplateDirect (GuardedAlt S) (Exp S)
deriving instance UniplateDirect (Decl S) (Pat S)
deriving instance UniplateDirect (IPBind S) (Pat S)
deriving instance UniplateDirect (GuardedAlts S) (Pat S)
deriving instance UniplateDirect (Maybe (Binds S)) (Pat S)
deriving instance UniplateDirect (ClassDecl S) (Exp S)
deriving instance UniplateDirect (InstDecl S) (Exp S)
deriving instance UniplateDirect (GuardedRhs S) (Exp S)
deriving instance UniplateDirect (Maybe [ClassDecl S]) (Pat S)
deriving instance UniplateDirect (Maybe [InstDecl S]) (Pat S)
deriving instance UniplateDirect (Match S) (Pat S)
deriving instance UniplateDirect (Rhs S) (Pat S)
deriving instance UniplateDirect (Rule S) (Pat S)
deriving instance UniplateDirect (GuardedAlt S) (Pat S)
deriving instance UniplateDirect (ClassDecl S) (Pat S)
deriving instance UniplateDirect (InstDecl S) (Pat S)
deriving instance UniplateDirect (GuardedRhs S) (Pat S)
deriving instance UniplateDirect (Maybe (Binds S)) (Decl S)
deriving instance UniplateDirect (Exp S) (Name S)
deriving instance UniplateDirect (Decl S)
deriving instance UniplateDirect (Binds S) (Decl S)
deriving instance UniplateDirect (Name S)
deriving instance UniplateDirect (QName S) (Name S)
deriving instance UniplateDirect (QOp S) (Name S)
deriving instance UniplateDirect (Pat S) (Name S)
deriving instance UniplateDirect (Binds S) (Name S)
deriving instance UniplateDirect (Alt S) (Name S)
deriving instance UniplateDirect (Stmt S) (Name S)
deriving instance UniplateDirect (Maybe (Exp S)) (Name S)
deriving instance UniplateDirect (FieldUpdate S) (Name S)
deriving instance UniplateDirect (QualStmt S) (Name S)
deriving instance UniplateDirect [QualStmt S] (Name S)
deriving instance UniplateDirect (Type S) (Name S)
deriving instance UniplateDirect (Bracket S) (Name S)
deriving instance UniplateDirect (Splice S) (Name S)
deriving instance UniplateDirect (XAttr S) (Name S)
deriving instance UniplateDirect (Decl S) (Name S)
deriving instance UniplateDirect (Exp S) (Decl S)
deriving instance UniplateDirect (GuardedAlts S) (Name S)
deriving instance UniplateDirect (IPBind S) (Decl S)
deriving instance UniplateDirect (IPBind S) (Name S)
deriving instance UniplateDirect (Kind S) (Name S)
deriving instance UniplateDirect (Match S) (Decl S)
deriving instance UniplateDirect (Maybe (Binds S)) (Name S)
deriving instance UniplateDirect (Maybe (Context S)) (Name S)
deriving instance UniplateDirect (Maybe (Pat S)) (Name S)
deriving instance UniplateDirect (Maybe [ClassDecl S]) (Decl S)
deriving instance UniplateDirect (Maybe [InstDecl S]) (Decl S)
deriving instance UniplateDirect (Maybe [TyVarBind S]) (Name S)
deriving instance UniplateDirect (PXAttr S) (Name S)
deriving instance UniplateDirect (Pat S) (Decl S)
deriving instance UniplateDirect (PatField S) (Name S)
deriving instance UniplateDirect (RPat S) (Name S)
deriving instance UniplateDirect (Rhs S) (Decl S)
deriving instance UniplateDirect (Rule S) (Decl S)
deriving instance UniplateDirect (Maybe [ClassDecl S]) (Name S)
deriving instance UniplateDirect (InstHead S) (Name S)
deriving instance UniplateDirect (Maybe [InstDecl S]) (Name S)
deriving instance UniplateDirect (Op S) (Name S)
deriving instance UniplateDirect (Match S) (Name S)
deriving instance UniplateDirect (Maybe (Type S)) (Name S)
deriving instance UniplateDirect (Rhs S) (Name S)
deriving instance UniplateDirect (Rule S) (Name S)
deriving instance UniplateDirect ([Name S], String) (Name S)
deriving instance UniplateDirect (Alt S) (Decl S)
deriving instance UniplateDirect (Stmt S) (Decl S)
deriving instance UniplateDirect (Maybe (Exp S)) (Decl S)
deriving instance UniplateDirect (FieldUpdate S) (Decl S)
deriving instance UniplateDirect (QualStmt S) (Decl S)
deriving instance UniplateDirect [QualStmt S] (Decl S)
deriving instance UniplateDirect (Bracket S) (Decl S)
deriving instance UniplateDirect (Splice S) (Decl S)
deriving instance UniplateDirect (XAttr S) (Decl S)
deriving instance UniplateDirect (GuardedAlt S) (Name S)
deriving instance UniplateDirect (Context S) (Name S)
deriving instance UniplateDirect (ClassDecl S) (Decl S)
deriving instance UniplateDirect (InstDecl S) (Decl S)
deriving instance UniplateDirect (TyVarBind S) (Name S)
deriving instance UniplateDirect (PatField S) (Decl S)
deriving instance UniplateDirect (RPat S) (Decl S)
deriving instance UniplateDirect (PXAttr S) (Decl S)
deriving instance UniplateDirect (Maybe (Pat S)) (Decl S)
deriving instance UniplateDirect (GuardedRhs S) (Decl S)
deriving instance UniplateDirect (DeclHead S) (Name S)
deriving instance UniplateDirect (Maybe (Kind S)) (Name S)
deriving instance UniplateDirect (QualConDecl S) (Name S)
deriving instance UniplateDirect (Maybe (Deriving S)) (Name S)
deriving instance UniplateDirect (GadtDecl S) (Name S)
deriving instance UniplateDirect (FunDep S) (Name S)
deriving instance UniplateDirect (ClassDecl S) (Name S)
deriving instance UniplateDirect (InstDecl S) (Name S)
deriving instance UniplateDirect (GuardedRhs S) (Name S)
deriving instance UniplateDirect (Maybe [RuleVar S]) (Name S)
deriving instance UniplateDirect (GuardedAlts S) (Decl S)
deriving instance UniplateDirect (Asst S) (Name S)
deriving instance UniplateDirect (ConDecl S) (Name S)
deriving instance UniplateDirect (Deriving S) (Name S)
deriving instance UniplateDirect (RuleVar S) (Name S)
deriving instance UniplateDirect (GuardedAlt S) (Decl S)
deriving instance UniplateDirect (BangType S) (Name S)
deriving instance UniplateDirect (FieldDecl S) (Name S)
deriving instance UniplateDirect (Module S) (FunDep S)
deriving instance UniplateDirect (Module S) (IPName S)
deriving instance UniplateDirect (Module S) (Decl S)
deriving instance UniplateDirect (Module S) (Kind S)
deriving instance UniplateDirect (Module S) (Pat S)
deriving instance UniplateDirect (Module S) (CallConv S)
deriving instance UniplateDirect (Module S) (GuardedRhs S)
deriving instance UniplateDirect (Module S) (GuardedAlt S)
deriving instance UniplateDirect (Module S) (PatField S)
deriving instance UniplateDirect (Module S) Boxed
deriving instance UniplateDirect (Module S) (ImportDecl S)
deriving instance UniplateDirect (Module S) (Exp S)
deriving instance UniplateDirect (Module S) (QualStmt S)
deriving instance UniplateDirect (Exp S) (CallConv S)
deriving instance UniplateDirect (GuardedRhs S)
deriving instance UniplateDirect (Decl S) (GuardedRhs S)
deriving instance UniplateDirect (XAttr S) (GuardedRhs S)
deriving instance UniplateDirect (Maybe (Exp S)) (GuardedRhs S)
deriving instance UniplateDirect (Exp S) (GuardedRhs S)
deriving instance UniplateDirect (GuardedAlt S)
deriving instance UniplateDirect (Decl S) (GuardedAlt S)
deriving instance UniplateDirect (XAttr S) (GuardedAlt S)
deriving instance UniplateDirect (Maybe (Exp S)) (GuardedAlt S)
deriving instance UniplateDirect (Exp S) (GuardedAlt S)
deriving instance UniplateDirect (PatField S)
deriving instance UniplateDirect (Decl S) (PatField S)
deriving instance UniplateDirect (XAttr S) (PatField S)
deriving instance UniplateDirect (Maybe (Exp S)) (PatField S)
deriving instance UniplateDirect (Exp S) (PatField S)
deriving instance UniplateDirect Boxed
deriving instance UniplateDirect (Maybe (ModuleHead S)) Boxed
deriving instance UniplateDirect (Decl S) Boxed
deriving instance UniplateDirect (XAttr S) Boxed
deriving instance UniplateDirect (Maybe (Exp S)) Boxed
deriving instance UniplateDirect (Exp S) Boxed
deriving instance UniplateDirect (ImportDecl S)
deriving instance UniplateDirect (QualStmt S)
deriving instance UniplateDirect (Decl S) (QualStmt S)
deriving instance UniplateDirect (XAttr S) (QualStmt S)
deriving instance UniplateDirect (Maybe (Exp S)) (QualStmt S)
deriving instance UniplateDirect (Exp S) (QualStmt S)
deriving instance UniplateDirect (Maybe (Type S)) Boxed
deriving instance UniplateDirect (Rhs S) Boxed
deriving instance UniplateDirect (Maybe (Binds S)) Boxed
deriving instance UniplateDirect (Rule S) Boxed
deriving instance UniplateDirect (QName S) Boxed
deriving instance UniplateDirect (QOp S) Boxed
deriving instance UniplateDirect (Binds S) Boxed
deriving instance UniplateDirect (Alt S) Boxed
deriving instance UniplateDirect (Stmt S) Boxed
deriving instance UniplateDirect (FieldUpdate S) Boxed
deriving instance UniplateDirect (QualStmt S) Boxed
deriving instance UniplateDirect [QualStmt S] Boxed
deriving instance UniplateDirect (Bracket S) Boxed
deriving instance UniplateDirect (Splice S) Boxed
deriving instance UniplateDirect (Stmt S) (QualStmt S)
deriving instance UniplateDirect (Maybe [ClassDecl S]) (QualStmt S)
deriving instance UniplateDirect (Maybe [InstDecl S]) (QualStmt S)
deriving instance UniplateDirect (Match S) (QualStmt S)
deriving instance UniplateDirect (Pat S) (QualStmt S)
deriving instance UniplateDirect (Rhs S) (QualStmt S)
deriving instance UniplateDirect (Maybe (Binds S)) (QualStmt S)
deriving instance UniplateDirect (Rule S) (QualStmt S)
deriving instance UniplateDirect (Binds S) (QualStmt S)
deriving instance UniplateDirect (Alt S) (QualStmt S)
deriving instance UniplateDirect (FieldUpdate S) (QualStmt S)
deriving instance UniplateDirect [QualStmt S] (QualStmt S)
deriving instance UniplateDirect (Bracket S) (QualStmt S)
deriving instance UniplateDirect (Splice S) (QualStmt S)
deriving instance UniplateDirect (FunDep S)
deriving instance UniplateDirect (Decl S) (FunDep S)
deriving instance UniplateDirect (XAttr S) (FunDep S)
deriving instance UniplateDirect (Maybe (Exp S)) (FunDep S)
deriving instance UniplateDirect (Exp S) (FunDep S)
deriving instance UniplateDirect (IPName S)
deriving instance UniplateDirect (Decl S) (IPName S)
deriving instance UniplateDirect (XAttr S) (IPName S)
deriving instance UniplateDirect (Maybe (Exp S)) (IPName S)
deriving instance UniplateDirect (Exp S) (IPName S)
deriving instance UniplateDirect (Kind S)
deriving instance UniplateDirect (Decl S) (Kind S)
deriving instance UniplateDirect (XAttr S) (Kind S)
deriving instance UniplateDirect (Maybe (Exp S)) (Kind S)
deriving instance UniplateDirect (Exp S) (Kind S)
deriving instance UniplateDirect (CallConv S)
deriving instance UniplateDirect (Decl S) (CallConv S)
deriving instance UniplateDirect (XAttr S) (CallConv S)
deriving instance UniplateDirect (Maybe (Exp S)) (CallConv S)
deriving instance UniplateDirect (CallConv S)
deriving instance UniplateDirect (Pat S) (CallConv S)
deriving instance UniplateDirect (Binds S) (CallConv S)
deriving instance UniplateDirect (Alt S) (CallConv S)
deriving instance UniplateDirect (Stmt S) (CallConv S)
deriving instance UniplateDirect (FieldUpdate S) (CallConv S)
deriving instance UniplateDirect (QualStmt S) (CallConv S)
deriving instance UniplateDirect [QualStmt S] (CallConv S)
deriving instance UniplateDirect (Bracket S) (CallConv S)
deriving instance UniplateDirect (Splice S) (CallConv S)
deriving instance UniplateDirect (Stmt S) (GuardedRhs S)
deriving instance UniplateDirect (Maybe [ClassDecl S]) (GuardedRhs S)
deriving instance UniplateDirect (Maybe [InstDecl S]) (GuardedRhs S)
deriving instance UniplateDirect (Match S) (GuardedRhs S)
deriving instance UniplateDirect (Pat S) (GuardedRhs S)
deriving instance UniplateDirect (Rhs S) (GuardedRhs S)
deriving instance UniplateDirect (Maybe (Binds S)) (GuardedRhs S)
deriving instance UniplateDirect (Rule S) (GuardedRhs S)
deriving instance UniplateDirect (Binds S) (GuardedRhs S)
deriving instance UniplateDirect (Alt S) (GuardedRhs S)
deriving instance UniplateDirect (FieldUpdate S) (GuardedRhs S)
deriving instance UniplateDirect (QualStmt S) (GuardedRhs S)
deriving instance UniplateDirect [QualStmt S] (GuardedRhs S)
deriving instance UniplateDirect (Bracket S) (GuardedRhs S)
deriving instance UniplateDirect (Splice S) (GuardedRhs S)
deriving instance UniplateDirect (Stmt S) (GuardedAlt S)
deriving instance UniplateDirect (Maybe [ClassDecl S]) (GuardedAlt S)
deriving instance UniplateDirect (Maybe [InstDecl S]) (GuardedAlt S)
deriving instance UniplateDirect (Match S) (GuardedAlt S)
deriving instance UniplateDirect (Pat S) (GuardedAlt S)
deriving instance UniplateDirect (Rhs S) (GuardedAlt S)
deriving instance UniplateDirect (Maybe (Binds S)) (GuardedAlt S)
deriving instance UniplateDirect (Rule S) (GuardedAlt S)
deriving instance UniplateDirect (Binds S) (GuardedAlt S)
deriving instance UniplateDirect (Alt S) (GuardedAlt S)
deriving instance UniplateDirect (FieldUpdate S) (GuardedAlt S)
deriving instance UniplateDirect (QualStmt S) (GuardedAlt S)
deriving instance UniplateDirect [QualStmt S] (GuardedAlt S)
deriving instance UniplateDirect (Bracket S) (GuardedAlt S)
deriving instance UniplateDirect (Splice S) (GuardedAlt S)
deriving instance UniplateDirect (Pat S) (PatField S)
deriving instance UniplateDirect (Maybe [ClassDecl S]) (PatField S)
deriving instance UniplateDirect (Maybe [InstDecl S]) (PatField S)
deriving instance UniplateDirect (Match S) (PatField S)
deriving instance UniplateDirect (Rhs S) (PatField S)
deriving instance UniplateDirect (Maybe (Binds S)) (PatField S)
deriving instance UniplateDirect (Rule S) (PatField S)
deriving instance UniplateDirect (Binds S) (PatField S)
deriving instance UniplateDirect (Alt S) (PatField S)
deriving instance UniplateDirect (Stmt S) (PatField S)
deriving instance UniplateDirect (FieldUpdate S) (PatField S)
deriving instance UniplateDirect (QualStmt S) (PatField S)
deriving instance UniplateDirect [QualStmt S] (PatField S)
deriving instance UniplateDirect (Bracket S) (PatField S)
deriving instance UniplateDirect (Splice S) (PatField S)
deriving instance UniplateDirect (ModuleHead S) Boxed
deriving instance UniplateDirect (Type S) Boxed
deriving instance UniplateDirect (Maybe (Context S)) Boxed
deriving instance UniplateDirect (QualConDecl S) Boxed
deriving instance UniplateDirect (Maybe (Deriving S)) Boxed
deriving instance UniplateDirect (GadtDecl S) Boxed
deriving instance UniplateDirect (Maybe [ClassDecl S]) Boxed
deriving instance UniplateDirect (InstHead S) Boxed
deriving instance UniplateDirect (Maybe [InstDecl S]) Boxed
deriving instance UniplateDirect (Match S) Boxed
deriving instance UniplateDirect (Pat S) Boxed
deriving instance UniplateDirect (GuardedRhs S) Boxed
deriving instance UniplateDirect (Maybe [RuleVar S]) Boxed
deriving instance UniplateDirect (SpecialCon S) Boxed
deriving instance UniplateDirect (IPBind S) Boxed
deriving instance UniplateDirect (GuardedAlts S) Boxed
deriving instance UniplateDirect (ClassDecl S) (QualStmt S)
deriving instance UniplateDirect (InstDecl S) (QualStmt S)
deriving instance UniplateDirect (PatField S) (QualStmt S)
deriving instance UniplateDirect (RPat S) (QualStmt S)
deriving instance UniplateDirect (PXAttr S) (QualStmt S)
deriving instance UniplateDirect (Maybe (Pat S)) (QualStmt S)
deriving instance UniplateDirect (GuardedRhs S) (QualStmt S)
deriving instance UniplateDirect (IPBind S) (QualStmt S)
deriving instance UniplateDirect (GuardedAlts S) (QualStmt S)
deriving instance UniplateDirect (Maybe [ClassDecl S]) (FunDep S)
deriving instance UniplateDirect (Maybe [InstDecl S]) (FunDep S)
deriving instance UniplateDirect (Match S) (FunDep S)
deriving instance UniplateDirect (Pat S) (FunDep S)
deriving instance UniplateDirect (Rhs S) (FunDep S)
deriving instance UniplateDirect (Maybe (Binds S)) (FunDep S)
deriving instance UniplateDirect (Rule S) (FunDep S)
deriving instance UniplateDirect (Binds S) (FunDep S)
deriving instance UniplateDirect (Alt S) (FunDep S)
deriving instance UniplateDirect (Stmt S) (FunDep S)
deriving instance UniplateDirect (FieldUpdate S) (FunDep S)
deriving instance UniplateDirect (QualStmt S) (FunDep S)
deriving instance UniplateDirect [QualStmt S] (FunDep S)
deriving instance UniplateDirect (Bracket S) (FunDep S)
deriving instance UniplateDirect (Splice S) (FunDep S)
deriving instance UniplateDirect (Type S) (IPName S)
deriving instance UniplateDirect (Maybe (Context S)) (IPName S)
deriving instance UniplateDirect (QualConDecl S) (IPName S)
deriving instance UniplateDirect (Maybe (Deriving S)) (IPName S)
deriving instance UniplateDirect (GadtDecl S) (IPName S)
deriving instance UniplateDirect (Maybe [ClassDecl S]) (IPName S)
deriving instance UniplateDirect (InstHead S) (IPName S)
deriving instance UniplateDirect (Maybe [InstDecl S]) (IPName S)
deriving instance UniplateDirect (Match S) (IPName S)
deriving instance UniplateDirect (Pat S) (IPName S)
deriving instance UniplateDirect (Maybe (Type S)) (IPName S)
deriving instance UniplateDirect (Rhs S) (IPName S)
deriving instance UniplateDirect (Maybe (Binds S)) (IPName S)
deriving instance UniplateDirect (Rule S) (IPName S)
deriving instance UniplateDirect (Binds S) (IPName S)
deriving instance UniplateDirect (Alt S) (IPName S)
deriving instance UniplateDirect (Stmt S) (IPName S)
deriving instance UniplateDirect (FieldUpdate S) (IPName S)
deriving instance UniplateDirect (QualStmt S) (IPName S)
deriving instance UniplateDirect [QualStmt S] (IPName S)
deriving instance UniplateDirect (Bracket S) (IPName S)
deriving instance UniplateDirect (Splice S) (IPName S)
deriving instance UniplateDirect (DeclHead S) (Kind S)
deriving instance UniplateDirect (Type S) (Kind S)
deriving instance UniplateDirect (Maybe (Kind S)) (Kind S)
deriving instance UniplateDirect (Maybe (Context S)) (Kind S)
deriving instance UniplateDirect (QualConDecl S) (Kind S)
deriving instance UniplateDirect (Maybe (Deriving S)) (Kind S)
deriving instance UniplateDirect (GadtDecl S) (Kind S)
deriving instance UniplateDirect (Maybe [ClassDecl S]) (Kind S)
deriving instance UniplateDirect (InstHead S) (Kind S)
deriving instance UniplateDirect (Maybe [InstDecl S]) (Kind S)
deriving instance UniplateDirect (Match S) (Kind S)
deriving instance UniplateDirect (Pat S) (Kind S)
deriving instance UniplateDirect (Maybe (Type S)) (Kind S)
deriving instance UniplateDirect (Rhs S) (Kind S)
deriving instance UniplateDirect (Maybe (Binds S)) (Kind S)
deriving instance UniplateDirect (Rule S) (Kind S)
deriving instance UniplateDirect (Binds S) (Kind S)
deriving instance UniplateDirect (Alt S) (Kind S)
deriving instance UniplateDirect (Stmt S) (Kind S)
deriving instance UniplateDirect (FieldUpdate S) (Kind S)
deriving instance UniplateDirect (QualStmt S) (Kind S)
deriving instance UniplateDirect [QualStmt S] (Kind S)
deriving instance UniplateDirect (Bracket S) (Kind S)
deriving instance UniplateDirect (Splice S) (Kind S)
deriving instance UniplateDirect (Maybe [ClassDecl S]) (CallConv S)
deriving instance UniplateDirect (Maybe [InstDecl S]) (CallConv S)
deriving instance UniplateDirect (Match S) (CallConv S)
deriving instance UniplateDirect (Rhs S) (CallConv S)
deriving instance UniplateDirect (Maybe (Binds S)) (CallConv S)
deriving instance UniplateDirect (Rule S) (CallConv S)
deriving instance UniplateDirect (PatField S) (CallConv S)
deriving instance UniplateDirect (RPat S) (CallConv S)
deriving instance UniplateDirect (PXAttr S) (CallConv S)
deriving instance UniplateDirect (Maybe (Pat S)) (CallConv S)
deriving instance UniplateDirect (IPBind S) (CallConv S)
deriving instance UniplateDirect (GuardedAlts S) (CallConv S)
deriving instance UniplateDirect (ClassDecl S) (GuardedRhs S)
deriving instance UniplateDirect (InstDecl S) (GuardedRhs S)
deriving instance UniplateDirect (PatField S) (GuardedRhs S)
deriving instance UniplateDirect (RPat S) (GuardedRhs S)
deriving instance UniplateDirect (PXAttr S) (GuardedRhs S)
deriving instance UniplateDirect (Maybe (Pat S)) (GuardedRhs S)
deriving instance UniplateDirect (IPBind S) (GuardedRhs S)
deriving instance UniplateDirect (GuardedAlts S) (GuardedRhs S)
deriving instance UniplateDirect (ClassDecl S) (GuardedAlt S)
deriving instance UniplateDirect (InstDecl S) (GuardedAlt S)
deriving instance UniplateDirect (PatField S) (GuardedAlt S)
deriving instance UniplateDirect (RPat S) (GuardedAlt S)
deriving instance UniplateDirect (PXAttr S) (GuardedAlt S)
deriving instance UniplateDirect (Maybe (Pat S)) (GuardedAlt S)
deriving instance UniplateDirect (GuardedRhs S) (GuardedAlt S)
deriving instance UniplateDirect (IPBind S) (GuardedAlt S)
deriving instance UniplateDirect (GuardedAlts S) (GuardedAlt S)
deriving instance UniplateDirect (RPat S) (PatField S)
deriving instance UniplateDirect (PXAttr S) (PatField S)
deriving instance UniplateDirect (Maybe (Pat S)) (PatField S)
deriving instance UniplateDirect (ClassDecl S) (PatField S)
deriving instance UniplateDirect (InstDecl S) (PatField S)
deriving instance UniplateDirect (GuardedRhs S) (PatField S)
deriving instance UniplateDirect (IPBind S) (PatField S)
deriving instance UniplateDirect (GuardedAlts S) (PatField S)
deriving instance UniplateDirect (Maybe (ExportSpecList S)) Boxed
deriving instance UniplateDirect (Context S) Boxed
deriving instance UniplateDirect (ConDecl S) Boxed
deriving instance UniplateDirect (Deriving S) Boxed
deriving instance UniplateDirect (ClassDecl S) Boxed
deriving instance UniplateDirect (InstDecl S) Boxed
deriving instance UniplateDirect (PatField S) Boxed
deriving instance UniplateDirect (RPat S) Boxed
deriving instance UniplateDirect (PXAttr S) Boxed
deriving instance UniplateDirect (Maybe (Pat S)) Boxed
deriving instance UniplateDirect (RuleVar S) Boxed
deriving instance UniplateDirect (GuardedAlt S) Boxed
deriving instance UniplateDirect (GuardedAlt S) (QualStmt S)
deriving instance UniplateDirect (ClassDecl S) (FunDep S)
deriving instance UniplateDirect (InstDecl S) (FunDep S)
deriving instance UniplateDirect (PatField S) (FunDep S)
deriving instance UniplateDirect (RPat S) (FunDep S)
deriving instance UniplateDirect (PXAttr S) (FunDep S)
deriving instance UniplateDirect (Maybe (Pat S)) (FunDep S)
deriving instance UniplateDirect (GuardedRhs S) (FunDep S)
deriving instance UniplateDirect (IPBind S) (FunDep S)
deriving instance UniplateDirect (GuardedAlts S) (FunDep S)
deriving instance UniplateDirect (Context S) (IPName S)
deriving instance UniplateDirect (ConDecl S) (IPName S)
deriving instance UniplateDirect (Deriving S) (IPName S)
deriving instance UniplateDirect (ClassDecl S) (IPName S)
deriving instance UniplateDirect (InstDecl S) (IPName S)
deriving instance UniplateDirect (PatField S) (IPName S)
deriving instance UniplateDirect (RPat S) (IPName S)
deriving instance UniplateDirect (PXAttr S) (IPName S)
deriving instance UniplateDirect (Maybe (Pat S)) (IPName S)
deriving instance UniplateDirect (GuardedRhs S) (IPName S)
deriving instance UniplateDirect (Maybe [RuleVar S]) (IPName S)
deriving instance UniplateDirect (IPBind S) (IPName S)
deriving instance UniplateDirect (GuardedAlts S) (IPName S)
deriving instance UniplateDirect (TyVarBind S) (Kind S)
deriving instance UniplateDirect (Maybe [TyVarBind S]) (Kind S)
deriving instance UniplateDirect (Context S) (Kind S)
deriving instance UniplateDirect (ConDecl S) (Kind S)
deriving instance UniplateDirect (Deriving S) (Kind S)
deriving instance UniplateDirect (ClassDecl S) (Kind S)
deriving instance UniplateDirect (InstDecl S) (Kind S)
deriving instance UniplateDirect (PatField S) (Kind S)
deriving instance UniplateDirect (RPat S) (Kind S)
deriving instance UniplateDirect (PXAttr S) (Kind S)
deriving instance UniplateDirect (Maybe (Pat S)) (Kind S)
deriving instance UniplateDirect (GuardedRhs S) (Kind S)
deriving instance UniplateDirect (Maybe [RuleVar S]) (Kind S)
deriving instance UniplateDirect (IPBind S) (Kind S)
deriving instance UniplateDirect (GuardedAlts S) (Kind S)
deriving instance UniplateDirect (ClassDecl S) (CallConv S)
deriving instance UniplateDirect (InstDecl S) (CallConv S)
deriving instance UniplateDirect (GuardedRhs S) (CallConv S)
deriving instance UniplateDirect (GuardedAlt S) (CallConv S)
deriving instance UniplateDirect (GuardedAlt S) (GuardedRhs S)
deriving instance UniplateDirect (GuardedAlt S) (PatField S)
deriving instance UniplateDirect (ExportSpecList S) Boxed
deriving instance UniplateDirect (Asst S) Boxed
deriving instance UniplateDirect (BangType S) Boxed
deriving instance UniplateDirect (FieldDecl S) Boxed
deriving instance UniplateDirect (GuardedAlt S) (FunDep S)
deriving instance UniplateDirect (Asst S) (IPName S)
deriving instance UniplateDirect (BangType S) (IPName S)
deriving instance UniplateDirect (FieldDecl S) (IPName S)
deriving instance UniplateDirect (RuleVar S) (IPName S)
deriving instance UniplateDirect (GuardedAlt S) (IPName S)
deriving instance UniplateDirect (Asst S) (Kind S)
deriving instance UniplateDirect (BangType S) (Kind S)
deriving instance UniplateDirect (FieldDecl S) (Kind S)
deriving instance UniplateDirect (RuleVar S) (Kind S)
deriving instance UniplateDirect (GuardedAlt S) (Kind S)
deriving instance UniplateDirect (ExportSpec S) Boxed
deriving instance UniplateDirect (Module S) (Splice S)
deriving instance UniplateDirect (Module S) (Bracket S)
deriving instance UniplateDirect (Splice S)
deriving instance UniplateDirect (Decl S) (Splice S)
deriving instance UniplateDirect (XAttr S) (Splice S)
deriving instance UniplateDirect (Maybe (Exp S)) (Splice S)
deriving instance UniplateDirect (Exp S) (Splice S)
deriving instance UniplateDirect (Bracket S)
deriving instance UniplateDirect (Decl S) (Bracket S)
deriving instance UniplateDirect (XAttr S) (Bracket S)
deriving instance UniplateDirect (Maybe (Exp S)) (Bracket S)
deriving instance UniplateDirect (Exp S) (Bracket S)
deriving instance UniplateDirect (Maybe [ClassDecl S]) (Splice S)
deriving instance UniplateDirect (Maybe [InstDecl S]) (Splice S)
deriving instance UniplateDirect (Match S) (Splice S)
deriving instance UniplateDirect (Pat S) (Splice S)
deriving instance UniplateDirect (Rhs S) (Splice S)
deriving instance UniplateDirect (Maybe (Binds S)) (Splice S)
deriving instance UniplateDirect (Rule S) (Splice S)
deriving instance UniplateDirect (Binds S) (Splice S)
deriving instance UniplateDirect (Alt S) (Splice S)
deriving instance UniplateDirect (Stmt S) (Splice S)
deriving instance UniplateDirect (FieldUpdate S) (Splice S)
deriving instance UniplateDirect (QualStmt S) (Splice S)
deriving instance UniplateDirect [QualStmt S] (Splice S)
deriving instance UniplateDirect (Bracket S) (Splice S)
deriving instance UniplateDirect (Pat S) (Bracket S)
deriving instance UniplateDirect (Maybe [ClassDecl S]) (Bracket S)
deriving instance UniplateDirect (Maybe [InstDecl S]) (Bracket S)
deriving instance UniplateDirect (Match S) (Bracket S)
deriving instance UniplateDirect (Rhs S) (Bracket S)
deriving instance UniplateDirect (Maybe (Binds S)) (Bracket S)
deriving instance UniplateDirect (Rule S) (Bracket S)
deriving instance UniplateDirect (Binds S) (Bracket S)
deriving instance UniplateDirect (Alt S) (Bracket S)
deriving instance UniplateDirect (Stmt S) (Bracket S)
deriving instance UniplateDirect (FieldUpdate S) (Bracket S)
deriving instance UniplateDirect (QualStmt S) (Bracket S)
deriving instance UniplateDirect [QualStmt S] (Bracket S)
deriving instance UniplateDirect (Splice S) (Bracket S)
deriving instance UniplateDirect (ClassDecl S) (Splice S)
deriving instance UniplateDirect (InstDecl S) (Splice S)
deriving instance UniplateDirect (PatField S) (Splice S)
deriving instance UniplateDirect (RPat S) (Splice S)
deriving instance UniplateDirect (PXAttr S) (Splice S)
deriving instance UniplateDirect (Maybe (Pat S)) (Splice S)
deriving instance UniplateDirect (GuardedRhs S) (Splice S)
deriving instance UniplateDirect (IPBind S) (Splice S)
deriving instance UniplateDirect (GuardedAlts S) (Splice S)
deriving instance UniplateDirect (PatField S) (Bracket S)
deriving instance UniplateDirect (RPat S) (Bracket S)
deriving instance UniplateDirect (PXAttr S) (Bracket S)
deriving instance UniplateDirect (Maybe (Pat S)) (Bracket S)
deriving instance UniplateDirect (ClassDecl S) (Bracket S)
deriving instance UniplateDirect (InstDecl S) (Bracket S)
deriving instance UniplateDirect (GuardedRhs S) (Bracket S)
deriving instance UniplateDirect (IPBind S) (Bracket S)
deriving instance UniplateDirect (GuardedAlts S) (Bracket S)
deriving instance UniplateDirect (GuardedAlt S) (Splice S)
deriving instance UniplateDirect (GuardedAlt S) (Bracket S)
deriving instance UniplateDirect (Exp S) (Exp S)
deriving instance UniplateDirect [Pat S] (Pat S)
deriving instance UniplateDirect (Module S) (Name S)
deriving instance UniplateDirect (Maybe (ModuleHead S)) (Name S)
deriving instance UniplateDirect (OptionPragma S) (Name S)
deriving instance UniplateDirect (ImportDecl S) (Name S)
deriving instance UniplateDirect (ModuleHead S) (Name S)
deriving instance UniplateDirect (Maybe (ImportSpecList S)) (Name S)
deriving instance UniplateDirect (Maybe (ExportSpecList S)) (Name S)
deriving instance UniplateDirect (ImportSpecList S) (Name S)
deriving instance UniplateDirect (ExportSpecList S) (Name S)
deriving instance UniplateDirect (ImportSpec S) (Name S)
deriving instance UniplateDirect (ExportSpec S) (Name S)
deriving instance UniplateDirect (CName S) (Name S)
deriving instance UniplateDirect [Stmt S] (Exp S)
deriving instance UniplateDirect (Decl S) (Type S)
deriving instance UniplateDirect (Type S)
deriving instance UniplateDirect (Maybe (Context S)) (Type S)
deriving instance UniplateDirect (QualConDecl S) (Type S)
deriving instance UniplateDirect (Maybe (Deriving S)) (Type S)
deriving instance UniplateDirect (GadtDecl S) (Type S)
deriving instance UniplateDirect (Maybe [ClassDecl S]) (Type S)
deriving instance UniplateDirect (InstHead S) (Type S)
deriving instance UniplateDirect (Maybe [InstDecl S]) (Type S)
deriving instance UniplateDirect (Exp S) (Type S)
deriving instance UniplateDirect (Match S) (Type S)
deriving instance UniplateDirect (Pat S) (Type S)
deriving instance UniplateDirect (Maybe (Type S)) (Type S)
deriving instance UniplateDirect (Rhs S) (Type S)
deriving instance UniplateDirect (Maybe (Binds S)) (Type S)
deriving instance UniplateDirect (Rule S) (Type S)
deriving instance UniplateDirect (Context S) (Type S)
deriving instance UniplateDirect (ConDecl S) (Type S)
deriving instance UniplateDirect (Deriving S) (Type S)
deriving instance UniplateDirect (ClassDecl S) (Type S)
deriving instance UniplateDirect (InstDecl S) (Type S)
deriving instance UniplateDirect (Binds S) (Type S)
deriving instance UniplateDirect (Alt S) (Type S)
deriving instance UniplateDirect (Stmt S) (Type S)
deriving instance UniplateDirect (Maybe (Exp S)) (Type S)
deriving instance UniplateDirect (FieldUpdate S) (Type S)
deriving instance UniplateDirect (QualStmt S) (Type S)
deriving instance UniplateDirect [QualStmt S] (Type S)
deriving instance UniplateDirect (Bracket S) (Type S)
deriving instance UniplateDirect (Splice S) (Type S)
deriving instance UniplateDirect (XAttr S) (Type S)
deriving instance UniplateDirect (PatField S) (Type S)
deriving instance UniplateDirect (RPat S) (Type S)
deriving instance UniplateDirect (PXAttr S) (Type S)
deriving instance UniplateDirect (Maybe (Pat S)) (Type S)
deriving instance UniplateDirect (GuardedRhs S) (Type S)
deriving instance UniplateDirect (Maybe [RuleVar S]) (Type S)
deriving instance UniplateDirect (Asst S) (Type S)
deriving instance UniplateDirect (BangType S) (Type S)
deriving instance UniplateDirect (FieldDecl S) (Type S)
deriving instance UniplateDirect (IPBind S) (Type S)
deriving instance UniplateDirect (GuardedAlts S) (Type S)
deriving instance UniplateDirect (RuleVar S) (Type S)
deriving instance UniplateDirect (GuardedAlt S) (Type S)
deriving instance UniplateDirect (Exp S) (QName S)
deriving instance UniplateDirect (QName S)
deriving instance UniplateDirect (QOp S) (QName S)
deriving instance UniplateDirect (Pat S) (QName S)
deriving instance UniplateDirect (Binds S) (QName S)
deriving instance UniplateDirect (Alt S) (QName S)
deriving instance UniplateDirect (Stmt S) (QName S)
deriving instance UniplateDirect (Maybe (Exp S)) (QName S)
deriving instance UniplateDirect (FieldUpdate S) (QName S)
deriving instance UniplateDirect (QualStmt S) (QName S)
deriving instance UniplateDirect [QualStmt S] (QName S)
deriving instance UniplateDirect (Type S) (QName S)
deriving instance UniplateDirect (Bracket S) (QName S)
deriving instance UniplateDirect (Splice S) (QName S)
deriving instance UniplateDirect (XAttr S) (QName S)
deriving instance UniplateDirect (PatField S) (QName S)
deriving instance UniplateDirect (RPat S) (QName S)
deriving instance UniplateDirect (PXAttr S) (QName S)
deriving instance UniplateDirect (Maybe (Pat S)) (QName S)
deriving instance UniplateDirect (Decl S) (QName S)
deriving instance UniplateDirect (IPBind S) (QName S)
deriving instance UniplateDirect (GuardedAlts S) (QName S)
deriving instance UniplateDirect (Maybe (Binds S)) (QName S)
deriving instance UniplateDirect (Maybe (Context S)) (QName S)
deriving instance UniplateDirect (QualConDecl S) (QName S)
deriving instance UniplateDirect (Maybe (Deriving S)) (QName S)
deriving instance UniplateDirect (GadtDecl S) (QName S)
deriving instance UniplateDirect (Maybe [ClassDecl S]) (QName S)
deriving instance UniplateDirect (InstHead S) (QName S)
deriving instance UniplateDirect (Maybe [InstDecl S]) (QName S)
deriving instance UniplateDirect (Match S) (QName S)
deriving instance UniplateDirect (Maybe (Type S)) (QName S)
deriving instance UniplateDirect (Rhs S) (QName S)
deriving instance UniplateDirect (Rule S) (QName S)
deriving instance UniplateDirect (GuardedAlt S) (QName S)
deriving instance UniplateDirect (Context S) (QName S)
deriving instance UniplateDirect (ConDecl S) (QName S)
deriving instance UniplateDirect (Deriving S) (QName S)
deriving instance UniplateDirect (ClassDecl S) (QName S)
deriving instance UniplateDirect (InstDecl S) (QName S)
deriving instance UniplateDirect (GuardedRhs S) (QName S)
deriving instance UniplateDirect (Maybe [RuleVar S]) (QName S)
deriving instance UniplateDirect (Asst S) (QName S)
deriving instance UniplateDirect (BangType S) (QName S)
deriving instance UniplateDirect (FieldDecl S) (QName S)
deriving instance UniplateDirect (RuleVar S) (QName S)
!-}
hlint-1.8.53/src/HSE/NameMatch.hs 0000644 0000000 0000000 00000006177 12220306165 014523 0 ustar 00 0000000 0000000
module HSE.NameMatch(
Scope, emptyScope, moduleScope, scopeImports,
NameMatch, nameMatch, nameQualify
) where
import HSE.Type
import HSE.Util
import Data.List
import Data.Maybe
{-
the hint file can do:
import Prelude (filter)
import Data.List (filter)
import List (filter)
then filter on it's own will get expanded to all of them
import Data.List
import List as Data.List
if Data.List.head x ==> x, then that might match List too
-}
type NameMatch = QName S -> QName S -> Bool
data Scope = Scope [ImportDecl S]
deriving Show
moduleScope :: Module S -> Scope
moduleScope xs = Scope $ [prelude | not $ any isPrelude res] ++ res
where
res = [x | x <- moduleImports xs, importPkg x /= Just "hint"]
prelude = ImportDecl an (ModuleName an "Prelude") False False Nothing Nothing Nothing
isPrelude x = fromModuleName (importModule x) == "Prelude"
emptyScope :: Scope
emptyScope = Scope []
scopeImports :: Scope -> [ImportDecl S]
scopeImports (Scope x) = x
-- given A B x y, does A{x} possibly refer to the same name as B{y}
-- this property is reflexive
nameMatch :: Scope -> Scope -> NameMatch
nameMatch a b x@Special{} y@Special{} = x =~= y
nameMatch a b x y | isSpecial x || isSpecial y = False
nameMatch a b x y = unqual x =~= unqual y && not (null $ possModules a x `intersect` possModules b y)
-- given A B x, return y such that A{x} == B{y}, if you can
nameQualify :: Scope -> Scope -> QName S -> QName S
nameQualify a (Scope b) x
| isSpecial x = x
| null imps = head $ real ++ [x]
| any (not . importQualified) imps = unqual x
| otherwise = Qual an (head $ mapMaybe importAs imps ++ map importModule imps) $ fromQual x
where
real = [Qual an (ModuleName an m) $ fromQual x | m <- possModules a x]
imps = [i | r <- real, i <- b, possImport i r]
-- which modules could a name possibly lie in
-- if it's qualified but not matching any import, assume the user
-- just lacks an import
possModules :: Scope -> QName S -> [String]
possModules (Scope is) x = f x
where
res = [fromModuleName $ importModule i | i <- is, possImport i x]
f Special{} = [""]
f x@(Qual _ mod _) = [fromModuleName mod | null res] ++ res
f _ = res
possImport :: ImportDecl S -> QName S -> Bool
possImport i Special{} = False
possImport i (Qual _ mod x) = fromModuleName mod `elem` map fromModuleName ms && possImport i{importQualified=False} (UnQual an x)
where ms = importModule i : maybeToList (importAs i)
possImport i (UnQual _ x) = not (importQualified i) && maybe True f (importSpecs i)
where
f (ImportSpecList _ hide xs) = if hide then Just True `notElem` ms else Nothing `elem` ms || Just True `elem` ms
where ms = map g xs
g :: ImportSpec S -> Maybe Bool -- does this import cover the name x
g (IVar _ y) = Just $ x =~= y
g (IAbs _ y) = Just $ x =~= y
g (IThingAll _ y) = if x =~= y then Just True else Nothing
g (IThingWith _ y ys) = Just $ x `elem_` (y : map fromCName ys)
fromCName :: CName S -> Name S
fromCName (VarName _ x) = x
fromCName (ConName _ x) = x
hlint-1.8.53/src/HSE/Match.hs 0000644 0000000 0000000 00000010305 12220306165 013706 0 ustar 00 0000000 0000000 {-# LANGUAGE ViewPatterns, MultiParamTypeClasses, FlexibleInstances, TypeSynonymInstances #-}
module HSE.Match where
import Data.Char
import HSE.Type
import HSE.Util
import qualified Language.Haskell.Exts as HSE_
class View a b where
view :: a -> b
data App2 = NoApp2 | App2 Exp_ Exp_ Exp_ deriving Show
instance View Exp_ App2 where
view (fromParen -> InfixApp _ lhs op rhs) = App2 (opExp op) lhs rhs
view (fromParen -> App _ (fromParen -> App _ f x) y) = App2 f x y
view _ = NoApp2
data App1 = NoApp1 | App1 Exp_ Exp_ deriving Show
instance View Exp_ App1 where
view (fromParen -> App _ f x) = App1 f x
view _ = NoApp1
data PVar_ = NoPVar_ | PVar_ String
instance View Pat_ PVar_ where
view (fromPParen -> PVar _ x) = PVar_ $ fromNamed x
view _ = NoPVar_
data Var_ = NoVar_ | Var_ String deriving Eq
instance View Exp_ Var_ where
view (fromParen -> Var _ (UnQual _ x)) = Var_ $ fromNamed x
view _ = NoVar_
(~=) :: Named a => a -> String -> Bool
(~=) = (==) . fromNamed
-- | fromNamed will return \"\" when it cannot be represented
-- toNamed may crash on \"\"
class Named a where
toNamed :: String -> a
fromNamed :: a -> String
isCtor (x:_) = isUpper x || x == ':'
isCtor _ = False
isSym (x:_) = not $ isAlpha x || x `elem` "_'"
isSym _ = False
instance Named (Exp S) where
fromNamed (Var _ x) = fromNamed x
fromNamed (Con _ x) = fromNamed x
fromNamed (List _ []) = "[]"
fromNamed _ = ""
toNamed "[]" = List an []
toNamed x | isCtor x = Con an $ toNamed x
| otherwise = Var an $ toNamed x
instance Named (QName S) where
fromNamed (Special _ Cons{}) = ":"
fromNamed (Special _ UnitCon{}) = "()"
fromNamed (UnQual _ x) = fromNamed x
fromNamed _ = ""
toNamed ":" = Special an $ Cons an
toNamed x = UnQual an $ toNamed x
instance Named HSE_.QName where
fromNamed (HSE_.Special HSE_.Cons) = ":"
fromNamed (HSE_.Special HSE_.UnitCon) = "()"
fromNamed (HSE_.UnQual x) = fromNamed x
fromNamed _ = ""
toNamed ":" = HSE_.Special HSE_.Cons
toNamed x = HSE_.UnQual $ toNamed x
instance Named (Name S) where
fromNamed (Ident _ x) = x
fromNamed (Symbol _ x) = x
toNamed x | isSym x = Symbol an x
| otherwise = Ident an x
instance Named HSE_.Name where
fromNamed (HSE_.Ident x) = x
fromNamed (HSE_.Symbol x) = x
toNamed x | isSym x = HSE_.Symbol x
| otherwise = HSE_.Ident x
instance Named (ModuleName S) where
fromNamed (ModuleName _ x) = x
toNamed = ModuleName an
instance Named (Pat S) where
fromNamed (PVar _ x) = fromNamed x
fromNamed (PApp _ x []) = fromNamed x
fromNamed _ = ""
toNamed x | isCtor x = PApp an (toNamed x) []
| otherwise = PVar an $ toNamed x
instance Named (TyVarBind S) where
fromNamed (KindedVar _ x _) = fromNamed x
fromNamed (UnkindedVar _ x) = fromNamed x
toNamed x = UnkindedVar an (toNamed x)
instance Named (QOp S) where
fromNamed (QVarOp _ x) = fromNamed x
fromNamed (QConOp _ x) = fromNamed x
toNamed x | isCtor x = QConOp an $ toNamed x
| otherwise = QVarOp an $ toNamed x
instance Named (Match S) where
fromNamed (Match _ x _ _ _) = fromNamed x
fromNamed (InfixMatch _ _ x _ _ _) = fromNamed x
toNamed = error "No toNamed for Match"
instance Named (DeclHead S) where
fromNamed (DHead _ x _) = fromNamed x
fromNamed (DHInfix _ _ x _) = fromNamed x
fromNamed (DHParen _ x) = fromNamed x
toNamed = error "No toNamed for DeclHead"
instance Named (Decl S) where
fromNamed (TypeDecl _ name _) = fromNamed name
fromNamed (DataDecl _ _ _ name _ _) = fromNamed name
fromNamed (GDataDecl _ _ _ name _ _ _) = fromNamed name
fromNamed (TypeFamDecl _ name _) = fromNamed name
fromNamed (DataFamDecl _ _ name _) = fromNamed name
fromNamed (ClassDecl _ _ name _ _) = fromNamed name
fromNamed (PatBind _ (PVar _ name) _ _ _) = fromNamed name
fromNamed (FunBind _ (name:_)) = fromNamed name
fromNamed (ForImp _ _ _ _ name _) = fromNamed name
fromNamed (ForExp _ _ _ name _) = fromNamed name
fromNamed (TypeSig _ (name:_) _) = fromNamed name
fromNamed _ = ""
toNamed = error "No toNamed for Decl"
hlint-1.8.53/src/HSE/FreeVars.hs 0000644 0000000 0000000 00000012224 12220306165 014371 0 ustar 00 0000000 0000000 {-# LANGUAGE FlexibleInstances #-}
module HSE.FreeVars(FreeVars, freeVars, vars, varss, pvars, declBind) where
import HSE.Type
import Data.Monoid
import qualified Data.Set as Set
import Data.Set(Set)
-- which names are bound by a declaration
declBind :: Decl_ -> [String]
declBind x = pvars x
vars x = Set.toList $ freeVars x
varss x = Set.toList $ free $ allVars x
pvars x = Set.toList $ bound $ allVars x
(^+) = Set.union
(^-) = Set.difference
data Vars = Vars {bound :: Set String, free :: Set String}
instance Monoid Vars where
mempty = Vars Set.empty Set.empty
mappend (Vars x1 x2) (Vars y1 y2) = Vars (x1 ^+ y1) (x2 ^+ y2)
mconcat fvs = Vars (Set.unions $ map bound fvs) (Set.unions $ map free fvs)
class AllVars a where
-- | Return the variables, erring on the side of more free variables
allVars :: a -> Vars
class FreeVars a where
-- | Return the variables, erring on the side of more free variables
freeVars :: a -> Set String
freeVars_ :: FreeVars a => a -> Vars
freeVars_ = Vars Set.empty . freeVars
inFree :: (AllVars a, FreeVars b) => a -> b -> Set String
inFree a b = free aa ^+ (freeVars b ^- bound aa)
where aa = allVars a
inVars :: (AllVars a, AllVars b) => a -> b -> Vars
inVars a b = Vars (bound aa ^+ bound bb) (free aa ^+ (free bb ^- bound aa))
where aa = allVars a
bb = allVars b
unqualNames :: QName S -> [String]
unqualNames (UnQual _ x) = [prettyPrint x]
unqualNames _ = []
unqualOp :: QOp S -> [String]
unqualOp (QVarOp _ x) = unqualNames x
unqualOp (QConOp _ x) = unqualNames x
instance FreeVars (Set String) where
freeVars = id
instance AllVars Vars where
allVars = id
instance FreeVars Exp_ where -- never has any bound variables
freeVars (Var _ x) = Set.fromList $ unqualNames x
freeVars (VarQuote l x) = freeVars $ Var l x
freeVars (SpliceExp _ (IdSplice _ x)) = Set.fromList [x]
freeVars (InfixApp _ a op b) = freeVars a ^+ Set.fromList (unqualOp op) ^+ freeVars b
freeVars (LeftSection _ a op) = freeVars a ^+ Set.fromList (unqualOp op)
freeVars (RightSection _ op b) = Set.fromList (unqualOp op) ^+ freeVars b
freeVars (Lambda _ p x) = inFree p x
freeVars (Let _ bind x) = inFree bind x
freeVars (Case _ x alts) = freeVars x `mappend` freeVars alts
freeVars (Do _ xs) = free $ allVars xs
freeVars (MDo l xs) = freeVars $ Do l xs
freeVars (ParComp _ x xs) = free xfv ^+ (freeVars x ^- bound xfv)
where xfv = mconcat $ map allVars xs
freeVars (ListComp l x xs) = freeVars $ ParComp l x [xs]
freeVars x = freeVars $ children x
instance FreeVars [Exp_] where
freeVars = Set.unions . map freeVars
instance AllVars Pat_ where
allVars (PVar _ x) = Vars (Set.singleton $ prettyPrint x) Set.empty
allVars (PNPlusK l x _) = allVars (PVar l x)
allVars (PAsPat l n x) = allVars (PVar l n) `mappend` allVars x
allVars (PWildCard _) = mempty -- explicitly cannot guess what might be bound here
allVars (PViewPat _ e p) = freeVars_ e `mappend` allVars p
allVars x = allVars $ children x
instance AllVars [Pat_] where
allVars = mconcat . map allVars
instance FreeVars (Alt S) where
freeVars (Alt _ pat alt bind) = inFree pat $ inFree bind alt
instance FreeVars [Alt S] where
freeVars = mconcat . map freeVars
instance FreeVars (GuardedAlts S) where
freeVars (UnGuardedAlt _ x) = freeVars x
freeVars (GuardedAlts _ xs) = mconcat $ map freeVars xs
instance FreeVars (GuardedAlt S) where
freeVars (GuardedAlt _ stmt exp) = inFree stmt exp
instance FreeVars (Rhs S) where
freeVars (UnGuardedRhs _ x) = freeVars x
freeVars (GuardedRhss _ xs) = mconcat $ map freeVars xs
instance FreeVars (GuardedRhs S) where
freeVars (GuardedRhs _ stmt exp) = inFree stmt exp
instance AllVars (QualStmt S) where
allVars (QualStmt _ x) = allVars x
allVars x = freeVars_ (childrenBi x :: [Exp_])
instance AllVars [QualStmt S] where
allVars (x:xs) = inVars x xs
allVars [] = mempty
instance AllVars [Stmt S] where
allVars (x:xs) = inVars x xs
allVars [] = mempty
instance AllVars (Stmt S) where
allVars (Generator _ pat exp) = allVars pat `mappend` freeVars_ exp
allVars (Qualifier _ exp) = freeVars_ exp
allVars (LetStmt _ binds) = allVars binds
allVars (RecStmt _ stmts) = allVars stmts
instance AllVars (Maybe (Binds S)) where
allVars = maybe mempty allVars
instance AllVars (Binds S) where
allVars (BDecls _ decls) = allVars decls
allVars (IPBinds _ binds) = freeVars_ binds
instance AllVars [Decl S] where
allVars = mconcat . map allVars
instance AllVars (Decl S) where
allVars (FunBind _ m) = allVars m
allVars (PatBind _ pat _ rhs bind) = allVars pat `mappend` freeVars_ (inFree bind rhs)
allVars _ = mempty
instance AllVars [Match S] where
allVars = mconcat . map allVars
instance AllVars (Match S) where
allVars (Match l name pat rhs binds) = allVars (PVar l name) `mappend` freeVars_ (inFree pat (inFree binds rhs))
allVars (InfixMatch l p1 name p2 rhs binds) = allVars $ Match l name (p1:p2) rhs binds
instance FreeVars [IPBind S] where
freeVars = mconcat . map freeVars
instance FreeVars (IPBind S) where
freeVars (IPBind _ _ exp) = freeVars exp
hlint-1.8.53/src/HSE/Evaluate.hs 0000644 0000000 0000000 00000001562 12220306165 014425 0 ustar 00 0000000 0000000 {-# LANGUAGE ViewPatterns #-}
-- Evaluate a HSE Exp as much as possible
module HSE.Evaluate(evaluate) where
import HSE.Match
import HSE.Util
import HSE.Type
import HSE.Bracket
evaluate :: Exp_ -> Exp_
evaluate = fromParen . transform evaluate1
evaluate1 :: Exp_ -> Exp_
evaluate1 (App s len (Lit _ (String _ xs _))) | len ~= "length" = Lit s $ Int s n (show n)
where n = fromIntegral $ length xs
evaluate1 (App s len (List _ xs)) | len ~= "length" = Lit s $ Int s n (show n)
where n = fromIntegral $ length xs
evaluate1 (view -> App2 op (Lit _ x) (Lit _ y)) | op ~= "==" = toNamed $ show $ x =~= y
evaluate1 (view -> App2 op (Lit _ (Int _ x _)) (Lit _ (Int _ y _)))
| op ~= ">=" = toNamed $ show $ x >= y
evaluate1 (view -> App2 op x y)
| op ~= "&&" && x ~= "True" = y
| op ~= "&&" && x ~= "False" = x
evaluate1 (Paren _ x) | isAtom x = x
evaluate1 x = x
hlint-1.8.53/src/HSE/Bracket.hs 0000644 0000000 0000000 00000010224 12220306165 014225 0 ustar 00 0000000 0000000 {-# LANGUAGE PatternGuards, TypeSynonymInstances, FlexibleInstances #-}
module HSE.Bracket where
import HSE.Type
import HSE.Util
import Util
class Brackets a where
remParen :: a -> Maybe a -- remove one paren, or Nothing if there is no paren
addParen :: a -> a -- write out a paren
-- | Is this item lexically requiring no bracketing ever
-- i.e. is totally atomic
isAtom :: a -> Bool
-- | Is the child safe free from brackets in the parent position.
-- Err on the side of caution, True = don't know
needBracket :: Int -> a -> a -> Bool
instance Brackets Exp_ where
remParen (Paren _ x) = Just x
remParen _ = Nothing
addParen = Paren an
isAtom x = case x of
Paren{} -> True
Tuple{} -> True
List{} -> True
LeftSection{} -> True
RightSection{} -> True
TupleSection{} -> True
RecConstr{} -> True
ListComp{} -> True
EnumFrom{} -> True
EnumFromTo{} -> True
EnumFromThen{} -> True
EnumFromThenTo{} -> True
_ -> isLexeme x
-- note: i is the index in children, not in the AST
needBracket i parent child
| isAtom child = False
| InfixApp{} <- parent, App{} <- child = False
| isSection parent, App{} <- child = False
| Let{} <- parent, App{} <- child = False
| ListComp{} <- parent = False
| List{} <- parent = False
| Tuple{} <- parent = False
| If{} <- parent, isAnyApp child = False
| App{} <- parent, i == 0, App{} <- child = False
| ExpTypeSig{} <- parent, i == 0, isApp child = False
| Paren{} <- parent = False
| isDotApp parent, isDotApp child, i == 1 = False
| RecConstr{} <- parent = False
| RecUpdate{} <- parent, i /= 0 = False
| Case{} <- parent, i /= 0 || isAnyApp child = False
| Lambda{} <- parent, i == length (universeBi parent :: [Pat_]) - 1 = False -- watch out for PViewPat
| Do{} <- parent = False
| otherwise = True
instance Brackets Type_ where
remParen (TyParen _ x) = Just x
remParen _ = Nothing
addParen = TyParen an
isAtom x = case x of
TyParen{} -> True
TyTuple{} -> True
TyList{} -> True
TyVar{} -> True
TyCon{} -> True
_ -> False
needBracket i parent child
| isAtom child = False
| TyFun{} <- parent, i == 1, TyFun{} <- child = False
| TyFun{} <- parent, TyApp{} <- child = False
| TyTuple{} <- parent = False
| TyList{} <- parent = False
| TyInfix{} <- parent, TyApp{} <- child = False
| TyParen{} <- parent = False
| otherwise = True
instance Brackets Pat_ where
remParen (PParen _ x) = Just x
remParen _ = Nothing
addParen = PParen an
isAtom x = case x of
PParen{} -> True
PTuple{} -> True
PList{} -> True
PVar{} -> True
PApp _ _ [] -> True
PWildCard{} -> True
_ -> False
needBracket i parent child
| isAtom child = False
| PTuple{} <- parent = False
| PList{} <- parent = False
| PInfixApp{} <- parent, PApp{} <- child = False
| PParen{} <- parent = False
| otherwise = True
-- | Add a Paren around something if it is not atomic
paren :: Exp_ -> Exp_
paren x = if isAtom x then x else addParen x
-- | Descend, and if something changes then add/remove brackets appropriately
descendBracket :: (Exp_ -> (Bool, Exp_)) -> Exp_ -> Exp_
descendBracket op x = descendIndex g x
where
g i y = if a then f i b else b
where (a,b) = op y
f i (Paren _ y) | not $ needBracket i x y = y
f i y | needBracket i x y = addParen y
f i y = y
transformBracket :: (Exp_ -> Maybe Exp_) -> Exp_ -> Exp_
transformBracket op = snd . g
where
g = f . descendBracket g
f x = maybe (False,x) ((,) True) (op x)
-- | Add/remove brackets as suggested needBracket at 1-level of depth
rebracket1 :: Exp_ -> Exp_
rebracket1 = descendBracket (\x -> (True,x))
-- a list of application, with any necessary brackets
appsBracket :: [Exp_] -> Exp_
appsBracket = foldl1 (\x -> rebracket1 . App an x)
hlint-1.8.53/src/HSE/All.hs 0000644 0000000 0000000 00000007020 12220306165 013362 0 ustar 00 0000000 0000000
module HSE.All(
module X,
ParseFlags(..), parseFlags, parseFlagsNoLocations,
parseFile, parseString, parseResult
) where
import HSE.Util as X
import HSE.Evaluate as X
import HSE.Type as X
import HSE.Bracket as X
import HSE.Match as X
import HSE.NameMatch as X
import HSE.FreeVars as X
import Util
import CmdLine
import Data.List
import Data.Maybe
import Language.Preprocessor.Cpphs
import qualified Data.Map as Map
data ParseFlags = ParseFlags
{cppFlags :: CppFlags
,language :: [Extension]
,encoding :: Encoding
,infixes :: [Fixity]
}
parseFlags :: ParseFlags
parseFlags = ParseFlags NoCpp defaultExtensions defaultEncoding []
parseFlagsNoLocations :: ParseFlags -> ParseFlags
parseFlagsNoLocations x = x{cppFlags = case cppFlags x of Cpphs y -> Cpphs $ f y; y -> y}
where f x = x{boolopts = (boolopts x){locations=False}}
runCpp :: CppFlags -> FilePath -> String -> IO String
runCpp NoCpp _ x = return x
runCpp CppSimple _ x = return $ unlines [if "#" `isPrefixOf` ltrim x then "" else x | x <- lines x]
runCpp (Cpphs o) file x = runCpphs o file x
---------------------------------------------------------------------
-- PARSING
-- | Parse a Haskell module
parseString :: ParseFlags -> FilePath -> String -> IO (String, ParseResult Module_)
parseString flags file str = do
ppstr <- runCpp (cppFlags flags) file str
return (ppstr, fmap (applyFixity fixity) $ parseFileContentsWithMode mode ppstr)
where
fixity = infixes flags ++ baseFixities
mode = defaultParseMode
{parseFilename = file
,extensions = language flags
,fixities = Nothing
,ignoreLinePragmas = False
}
parseFile :: ParseFlags -> FilePath -> IO (String, ParseResult Module_)
parseFile flags file = do
src <- readFileEncoding (encoding flags) file
parseString flags file src
-- throw an error if the parse is invalid
parseResult :: IO (String, ParseResult Module_) -> IO Module_
parseResult x = do
(_, res) <- x
return $! fromParseResult res
---------------------------------------------------------------------
-- FIXITIES
-- resolve fixities later, so we don't ever get uncatchable ambiguity errors
-- if there are fixity errors, try the cheapFixities (which never fails)
applyFixity :: [Fixity] -> Module_ -> Module_
applyFixity base modu = descendBi f modu
where
f x = fromMaybe (cheapFixities fixs x) $ applyFixities fixs x :: Decl_
fixs = concatMap getFixity (moduleDecls modu) ++ base
-- Apply fixities, but ignoring any ambiguous fixity errors and skipping qualified names,
-- local infix declarations etc. Only use as a backup, if HSE gives an error.
--
-- Inspired by the code at:
-- http://hackage.haskell.org/trac/haskell-prime/attachment/wiki/FixityResolution/resolve.hs
cheapFixities :: [Fixity] -> Decl_ -> Decl_
cheapFixities fixs = descendBi (transform f)
where
ask = askFixity fixs
f o@(InfixApp s1 (InfixApp s2 x op1 y) op2 z)
| p1 == p2 && (a1 /= a2 || a1 == AssocNone) = o -- Ambiguous infix expression!
| p1 > p2 || p1 == p2 && (a1 == AssocLeft || a2 == AssocNone) = o
| otherwise = InfixApp s1 x op1 (f $ InfixApp s1 y op2 z)
where
(a1,p1) = ask op1
(a2,p2) = ask op2
f x = x
askFixity :: [Fixity] -> QOp S -> (Assoc, Int)
askFixity xs = \k -> Map.findWithDefault (AssocLeft, 9) (fromNamed k) mp
where
mp = Map.fromList [(s,(a,p)) | Fixity a p x <- xs, let s = fromNamed x, s /= ""]
hlint-1.8.53/src/Hint/ 0000755 0000000 0000000 00000000000 12220306165 012602 5 ustar 00 0000000 0000000 hlint-1.8.53/src/Hint/Util.hs 0000644 0000000 0000000 00000005266 12220306165 014064 0 ustar 00 0000000 0000000 {-# LANGUAGE PatternGuards, ViewPatterns #-}
module Hint.Util where
import HSE.All
import Util
-- | Generate a lambda, but prettier (if possible).
-- Generally no lambda is good, but removing just some arguments isn't so useful.
niceLambda :: [String] -> Exp_ -> Exp_
-- \xs -> (e) ==> \xs -> e
niceLambda xs (Paren _ x) = niceLambda xs x
-- \xs -> \v vs -> e ==> \xs v -> \vs -> e
-- \xs -> \ -> e ==> \xs -> e
niceLambda xs (Lambda _ ((view -> PVar_ v):vs) x) | v `notElem` xs = niceLambda (xs++[v]) (Lambda an vs x)
niceLambda xs (Lambda _ [] x) = niceLambda xs x
-- \ -> e ==> e
niceLambda [] x = x
-- \xs -> e xs ==> e
niceLambda xs (fromApps -> e) | map view xs2 == map Var_ xs, vars e2 `disjoint` xs, notNull e2 = apps e2
where (e2,xs2) = splitAt (length e - length xs) e
-- \x y -> x + y ==> (+)
niceLambda [x,y] (InfixApp _ (view -> Var_ x1) (opExp -> op) (view -> Var_ y1))
| x == x1, y == y1, vars op `disjoint` [x,y] = op
-- \x -> x + b ==> (+ b) [heuristic, b must be a single lexeme, or gets too complex]
niceLambda [x] (view -> App2 (expOp -> Just op) a b)
| isLexeme b, view a == Var_ x, x `notElem` vars b, allowRightSection (fromNamed op) = rebracket1 $ RightSection an op b
-- \x y -> f y x = flip f
niceLambda [x,y] (view -> App2 op (view -> Var_ y1) (view -> Var_ x1))
| x == x1, y == y1, vars op `disjoint` [x,y] = App an (toNamed "flip") op
-- \x -> f (b x) ==> f . b
-- \x -> f $ b x ==> f . b
niceLambda [x] y | Just z <- factor y, x `notElem` vars z = z
where
-- factor the expression with respect to x
factor y@App{} | (ini,lst) <- unsnoc $ fromApps y, view lst == Var_ x = Just $ apps ini
factor y@App{} | (ini,lst) <- unsnoc $ fromApps y, Just z <- factor lst = Just $ niceDotApp (apps ini) z
factor (InfixApp _ y op (factor -> Just z)) | isDol op = Just $ niceDotApp y z
factor (Paren _ y@App{}) = factor y
factor _ = Nothing
-- \x -> (x +) ==> (+)
niceLambda [x] (LeftSection _ (view -> Var_ x1) op) | x == x1 = opExp op
-- base case
niceLambda ps x = Lambda an (map toNamed ps) x
-- ($) . b ==> b
niceDotApp :: Exp_ -> Exp_ -> Exp_
niceDotApp a b | a ~= "$" = b
| otherwise = dotApp a b
-- | Convert expressions which have redundant junk in them away.
-- Mainly so that later stages can match on fewer alternatives.
simplifyExp :: Exp_ -> Exp_
simplifyExp (InfixApp _ x dol y) | isDol dol = App an x (paren y)
simplifyExp (Let _ (BDecls _ [PatBind _ (view -> PVar_ x) Nothing (UnGuardedRhs _ y) Nothing]) z)
| x `notElem` vars y && length [() | UnQual _ a <- universeS z, prettyPrint a == x] <= 1 = transform f z
where f (view -> Var_ x') | x == x' = paren y
f x = x
simplifyExp x = x
hlint-1.8.53/src/Hint/Type.hs 0000644 0000000 0000000 00000000603 12220306165 014056 0 ustar 00 0000000 0000000
module Hint.Type(module Hint.Type, module Idea, module HSE.All) where
import HSE.All
import Idea
type DeclHint = Scope -> Module_ -> Decl_ -> [Idea]
type ModuHint = Scope -> Module_ -> [Idea]
type CrossHint = [(Scope, Module_)] -> [Idea]
data Hint = DeclHint {declHint :: DeclHint}
| ModuHint {moduHint :: ModuHint}
| CrossHint {crossHint :: CrossHint}
hlint-1.8.53/src/Hint/Structure.hs 0000644 0000000 0000000 00000012117 12220306165 015140 0 ustar 00 0000000 0000000 {-# LANGUAGE ViewPatterns #-}
{-
Improve the structure of code
yes x y = if a then b else if c then d else e -- yes x y ; | a = b ; | c = d ; | otherwise = e
x `yes` y = if a then b else if c then d else e -- yes x y ; | a = b ; | c = d ; | otherwise = e
no x y = if a then b else c
-- foo b | c <- f b = c -- foo (f -> c) = c
-- foo x y b z | c:cs <- f g b = c -- foo x y (f g -> c:cs) z = c
foo b | c <- f b = c + b
foo b | c <- f b = c where f = here
foo b | c <- f b = c where foo = b
foo b | c <- f b = c \
| c <- f b = c
foo x = yes x x where yes x y = if a then b else if c then d else e -- yes x y ; | a = b ; | c = d ; | otherwise = e
foo x | otherwise = y -- foo x = y
-- FIXME: #358 foo x = x + x where -- foo x = x + x
foo x | a = b | True = d -- foo x | a = b ; | otherwise = d
foo (Bar _ _ _ _) = x -- Bar{}
foo (Bar _ x _ _) = x
foo (Bar _ _) = x
foo = case f v of _ -> x -- x
foo = case v of v -> x -- x
foo = case v of z -> z
foo = case v of _ | False -> x
foo = case v of !True -> x -- True
foo = case v of !(Just x) -> x -- (Just x)
foo = case v of !(x : xs) -> x -- (x:xs)
foo = case v of !1 -> x -- 1
foo = case v of !x -> x
foo = let ~x = 1 in y -- x
foo = let ~(x:xs) = y in z
-}
module Hint.Structure where
import Hint.Type
import Util
structureHint :: DeclHint
structureHint _ _ x =
concatMap (uncurry hints . swap) (asPattern x) ++
concatMap patHint (universeBi x) ++
concatMap expHint (universeBi x)
hints :: (String -> Pattern -> Idea) -> Pattern -> [Idea]
hints gen (Pattern pat (UnGuardedRhs d bod) bind)
| length guards > 2 = [gen "Use guards" $ Pattern pat (GuardedRhss d guards) bind]
where guards = asGuards bod
{-
-- Do not suggest view patterns, they aren't something everyone likes sufficiently
hints gen (Pattern pats (GuardedRhss _ [GuardedRhs _ [Generator _ pat (App _ op (view -> Var_ p))] bod]) bind)
| Just i <- findIndex (=~= (toNamed p :: Pat_)) pats
, p `notElem` (vars bod ++ vars bind)
, vars op `disjoint` decsBind, pvars pats `disjoint` vars op, pvars pat `disjoint` pvars pats
= [gen "Use view patterns" $
Pattern (take i pats ++ [PParen an $ PViewPat an op pat] ++ drop (i+1) pats) (UnGuardedRhs an bod) bind]
where
decsBind = nub $ concatMap declBind $ childrenBi bind
-}
hints gen (Pattern pats (GuardedRhss _ [GuardedRhs _ [test] bod]) bind)
| prettyPrint test `elem` ["otherwise","True"]
= [gen "Redundant guard" $ Pattern pats (UnGuardedRhs an bod) bind]
hints gen (Pattern pats bod (Just bind)) | f bind && False -- disabled due to bug 358
= [gen "Redundant where" $ Pattern pats bod Nothing]
where
f (BDecls _ x) = null x
f (IPBinds _ x) = null x
hints gen (Pattern pats (GuardedRhss _ (unsnoc -> (gs, GuardedRhs _ [test] bod))) bind)
| prettyPrint test == "True"
= [gen "Use otherwise" $ Pattern pats (GuardedRhss an $ gs ++ [GuardedRhs an [Qualifier an $ toNamed "otherwise"] bod]) bind]
hints _ _ = []
asGuards :: Exp_ -> [GuardedRhs S]
asGuards (Paren _ x) = asGuards x
asGuards (If _ a b c) = GuardedRhs an [Qualifier an a] b : asGuards c
asGuards x = [GuardedRhs an [Qualifier an $ toNamed "otherwise"] x]
data Pattern = Pattern [Pat_] (Rhs S) (Maybe (Binds S))
-- Invariant: Number of patterns may not change
asPattern :: Decl_ -> [(Pattern, String -> Pattern -> Idea)]
asPattern x = concatMap decl (universeBi x) ++ concatMap alt (universeBi x)
where
decl o@(PatBind a pat b rhs bind) = [(Pattern [pat] rhs bind, \msg (Pattern [pat] rhs bind) -> warn msg o $ PatBind a pat b rhs bind)]
decl (FunBind _ xs) = map match xs
decl _ = []
match o@(Match a b pat rhs bind) = (Pattern pat rhs bind, \msg (Pattern pat rhs bind) -> warn msg o $ Match a b pat rhs bind)
match o@(InfixMatch a p b ps rhs bind) = (Pattern (p:ps) rhs bind, \msg (Pattern (p:ps) rhs bind) -> warn msg o $ InfixMatch a p b ps rhs bind)
alt o@(Alt a pat rhs bind) = [(Pattern [pat] (fromGuardedAlts rhs) bind, \msg (Pattern [pat] rhs bind) -> warn msg o $ Alt a pat (toGuardedAlts rhs) bind)]
-- Should these hints be in the same module? They are less structure, and more about pattern matching
-- Or perhaps the entire module should be renamed Pattern, since it's all about patterns
patHint :: Pat_ -> [Idea]
patHint o@(PApp _ name args) | length args >= 3 && all isPWildCard args = [warn "Use record patterns" o $ PRec an name []]
patHint o@(PBangPat _ x) | f x = [err "Redundant bang pattern" o x]
where f (PParen _ x) = f x
f (PAsPat _ _ x) = f x
f PLit{} = True
f PApp{} = True
f PInfixApp{} = True
f _ = False
patHint o@(PIrrPat _ x) | f x = [err "Redundant irrefutable pattern" o x]
where f (PParen _ x) = f x
f (PAsPat _ _ x) = f x
f PWildCard{} = True
f PVar{} = True
f _ = False
patHint _ = []
expHint :: Exp_ -> [Idea]
expHint o@(Case _ _ [Alt _ PWildCard{} (UnGuardedAlt _ e) Nothing]) = [warn "Redundant case" o e]
expHint o@(Case _ (Var _ x) [Alt _ (PVar _ y) (UnGuardedAlt _ e) Nothing])
| x =~= UnQual an y = [warn "Redundant case" o e]
expHint _ = []
hlint-1.8.53/src/Hint/Pragma.hs 0000644 0000000 0000000 00000005054 12220306165 014351 0 ustar 00 0000000 0000000 {-
Suggest better pragmas
OPTIONS_GHC -cpp => LANGUAGE CPP
OPTIONS_GHC -fglasgow-exts => LANGUAGE ... (in HSE)
OPTIONS_GHC -XFoo => LANGUAGE Foo
LANGUAGE A, A => LANGUAGE A
-- do not do LANGUAGE A, LANGUAGE B to combine
{-# OPTIONS_GHC -cpp #-} -- {-# LANGUAGE CPP #-}
{-# OPTIONS -cpp #-} -- {-# LANGUAGE CPP #-}
{-# OPTIONS_YHC -cpp #-}
{-# OPTIONS_GHC -XFoo #-} -- {-# LANGUAGE Foo #-}
{-# OPTIONS_GHC -fglasgow-exts #-} -- ???
{-# LANGUAGE A, B, C, A #-} -- {-# LANGUAGE A, B, C #-}
{-# LANGUAGE A #-}
{-# OPTIONS_GHC -cpp -foo #-} -- {-# LANGUAGE CPP #-} {-# OPTIONS_GHC -foo #-}
{-# OPTIONS_GHC -cpp #-} \
{-# LANGUAGE CPP, Text #-} --
{-# LANGUAGE A #-} \
{-# LANGUAGE B #-}
{-# LANGUAGE A #-} \
{-# LANGUAGE B, A #-} -- {-# LANGUAGE A, B #-}
-}
module Hint.Pragma where
import Hint.Type
import Data.List
import Data.Maybe
import Util
pragmaHint :: ModuHint
pragmaHint _ x = languageDupes lang ++ [pragmaIdea old $ [LanguagePragma an (map toNamed ns2) | ns2 /= []] ++ catMaybes new | old /= []]
where
lang = [x | x@LanguagePragma{} <- modulePragmas x]
(old,new,ns) = unzip3 [(old,new,ns) | old <- modulePragmas x, Just (new,ns) <- [optToLanguage old]]
ns2 = nub (concat ns) \\ concat [map fromNamed n | LanguagePragma _ n <- lang]
pragmaIdea :: [ModulePragma S] -> [ModulePragma S] -> Idea
pragmaIdea xs ys = rawIdea Error "Use better pragmas" (toSrcLoc $ ann $ head xs) (f xs) (f ys) []
where f = unlines . map prettyPrint
languageDupes :: [ModulePragma S] -> [Idea]
languageDupes [] = []
languageDupes (a@(LanguagePragma _ x):xs) =
(if nub_ x `neqList` x
then [pragmaIdea [a] [LanguagePragma an $ nub_ x]]
else [pragmaIdea [a,b] [LanguagePragma an (nub_ $ x ++ y)] | b@(LanguagePragma _ y) <- xs, notNull $ intersect_ x y]) ++
languageDupes xs
-- Given a pragma, can you extract some language features out
strToLanguage :: String -> Maybe [String]
strToLanguage "-cpp" = Just ["CPP"]
strToLanguage x | "-X" `isPrefixOf` x = Just [drop 2 x]
strToLanguage "-fglasgow-exts" = Just $ map show glasgowExts
strToLanguage _ = Nothing
optToLanguage :: ModulePragma S -> Maybe (Maybe (ModulePragma S), [String])
optToLanguage (OptionsPragma sl tool val)
| maybe True (== GHC) tool && any isJust vs = Just (res, concat $ catMaybes vs)
where
strs = words val
vs = map strToLanguage strs
keep = concat $ zipWith (\v s -> [s | isNothing v]) vs strs
res = if null keep then Nothing else Just $ OptionsPragma sl tool (unwords keep)
optToLanguage _ = Nothing
hlint-1.8.53/src/Hint/Naming.hs 0000644 0000000 0000000 00000006106 12220306165 014352 0 ustar 00 0000000 0000000 {-# LANGUAGE FlexibleContexts #-}
{-
Suggest the use of camelCase
Only permit:
_*[A-Za-z]*_*#*'*
Apply this to things that would get exported by default only
Also allow prop_ as it's a standard QuickCheck idiom
Also allow case_ as it's a standard test-framework-th idiom
Also don't suggest anything mentioned elsewhere in the module
data Yes = Foo | Bar'Test -- data Yes = Foo | BarTest
data Yes = Bar | Test_Bar -- data Yes = Bar | TestBar
data No = a :::: b
data Yes = Foo {bar_cap :: Int} -- data Yes = Foo{barCap :: Int}
data No = FOO | BarBAR | BarBBar
yes_foo = yes_foo + yes_foo -- yesFoo = ...
no = 1 where yes_foo = 2
a -== b = 1
myTest = 1; my_test = 1
semiring'laws = 1 -- semiringLaws = ...
data Yes = FOO_A | Foo_B -- data Yes = FOO_A | FooB
case_foo = 1
cast_foo = 1 -- castFoo = ...
runMutator# = 1
-}
module Hint.Naming(namingHint) where
import Hint.Type
import Data.List
import Data.Char
import Data.Maybe
import Util
import qualified Data.Set as Set
namingHint :: DeclHint
namingHint _ modu = naming $ Set.fromList [x | Ident _ x <- universeS modu]
naming :: Set.Set String -> Decl_ -> [Idea]
naming seen x = [warn "Use camelCase" x2 (replaceNames res x2) | notNull res]
where res = [(n,y) | n <- nub $ getNames x, Just y <- [suggestName n], not $ y `Set.member` seen]
x2 = shorten x
shorten :: Decl_ -> Decl_
shorten x = case x of
FunBind sl (Match a b c d _:_) -> FunBind sl [f (Match a b c) d]
PatBind a b c d _ -> f (PatBind a b c) d
x -> x
where
dots = Var an $ UnQual an $ Ident an "..." -- Must be an Ident, not a Symbol
f cont (UnGuardedRhs _ _) = cont (UnGuardedRhs an dots) Nothing
f cont (GuardedRhss _ _) = cont (GuardedRhss an [GuardedRhs an [Qualifier an dots] dots]) Nothing
getNames :: Decl_ -> [String]
getNames x = case x of
FunBind{} -> name
PatBind{} -> name
TypeDecl{} -> name
DataDecl _ _ _ _ cons _ -> name ++ [fromNamed x | QualConDecl _ _ _ x <- cons, x <- f x]
GDataDecl _ _ _ _ _ cons _ -> name ++ [fromNamed x | GadtDecl _ x _ <- cons]
TypeFamDecl{} -> name
DataFamDecl{} -> name
ClassDecl{} -> name
_ -> []
where
name = [fromNamed x]
f (ConDecl _ x _) = [x]
f (InfixConDecl _ _ x _) = [x]
f (RecDecl _ x ys) = x : concat [y | FieldDecl _ y _ <- ys]
suggestName :: String -> Maybe String
suggestName x = listToMaybe [f x | not $ isSym x || good || not (any isLower x) || "prop_" `isPrefixOf` x || "case_" `isPrefixOf` x]
where
good = all isAlphaNum $ drp '_' $ drp '#' $ drp '\'' $ reverse $ drp '_' x
drp x = dropWhile (== x)
f xs = us ++ g ys
where (us,ys) = span (== '_') xs
g x | x `elem` ["_","'","_'"] = x
g (a:x:xs) | a `elem` "_'" && isAlphaNum x = toUpper x : g xs
g (x:xs) | isAlphaNum x = x : g xs
| otherwise = g xs
g [] = []
replaceNames :: Biplate a (Name S) => [(String,String)] -> a -> a
replaceNames rep = descendBi f
where f (Ident _ x) = Ident an $ fromMaybe x $ lookup x rep
f x = x
hlint-1.8.53/src/Hint/Monad.hs 0000644 0000000 0000000 00000007647 12220306165 014212 0 ustar 00 0000000 0000000 {-# LANGUAGE ViewPatterns, PatternGuards #-}
{-
Find and match:
mapM, foldM, forM, replicateM, sequence, zipWithM
not at the last line of a do statement, or to the left of >>
Use let x = y instead of x <- return y, unless x is contained
within y, or bound more than once in that do block.
yes = do mapM print a; return b -- mapM_ print a
no = mapM print a
no = do foo ; mapM print a
yes = do (bar+foo) -- (bar+foo)
no = do bar ; foo
yes = do bar; a <- foo; return a -- do bar; foo
no = do bar; a <- foo; return b
yes = do x <- bar; x -- do join bar
no = do x <- bar; x; x
no = mdo hook <- mkTrigger pat (act >> rmHook hook) ; return hook
yes = do x <- return y; foo x -- @Warning do let x = y; foo x
yes = do x <- return $ y + z; foo x -- do let x = y + z; foo x
no = do x <- return x; foo x
no = do x <- return y; x <- return y; foo x
yes = do forM files $ \x -> return (); return () -- forM_ files $ \x -> return ()
yes = do if a then forM x y else sequence z q; return () -- if a then forM_ x y else sequence_ z q
yes = do case a of {_ -> forM x y; x:xs -> forM x xs}; return () -- case a of _ -> forM_ x y ; x:xs -> forM_ x xs
foldM_ f a xs = foldM f a xs >> return ()
folder f a xs = foldM f a xs >> return () -- foldM_ f a xs
yes = mapM async ds >>= mapM wait >> return () -- mapM async ds >>= mapM_ wait
-}
module Hint.Monad where
import Control.Arrow
import Data.Maybe
import Data.List
import Hint.Type
badFuncs = ["mapM","foldM","forM","replicateM","sequence","zipWithM"]
monadHint :: DeclHint
monadHint _ _ d = concatMap (monadExp d) $ universeBi d
monadExp :: Decl_ -> Exp_ -> [Idea]
monadExp decl x = case x of
(view -> App2 op x1 x2) | op ~= ">>" -> f x1
Do _ xs -> [err "Redundant return" x y | Just y <- [monadReturn xs]] ++
[err "Use join" x (Do an y) | Just y <- [monadJoin xs]] ++
[err "Redundant do" x y | [Qualifier _ y] <- [xs]] ++
[warn "Use let" x (Do an y) | Just y <- [monadLet xs]] ++
concat [f x | Qualifier _ x <- init xs]
_ -> []
where
f x = [err ("Use " ++ name) x y | Just (name,y) <- [monadCall x], fromNamed decl /= name]
-- see through Paren and down if/case etc
-- return the name to use in the hint, and the revised expression
monadCall :: Exp_ -> Maybe (String,Exp_)
monadCall (Paren _ x) = fmap (second $ Paren an) $ monadCall x
monadCall (App _ x y) = fmap (second $ \x -> App an x y) $ monadCall x
monadCall (InfixApp _ x op y)
| isDol op = fmap (second $ \x -> InfixApp an x op y) $ monadCall x
| op ~= ">>=" = fmap (second $ \y -> InfixApp an x op y) $ monadCall y
monadCall (replaceBranches -> (bs@(_:_), gen)) | all isJust res
= Just (fst $ fromJust $ head res, gen $ map (snd . fromJust) res)
where res = map monadCall bs
monadCall x | x:_ <- filter (x ~=) badFuncs = let x2 = x ++ "_" in Just (x2, toNamed x2)
monadCall _ = Nothing
monadReturn (reverse -> Qualifier _ (App _ ret (Var _ v)):Generator _ (PVar _ p) x:rest)
| ret ~= "return", fromNamed v == fromNamed p
= Just $ Do an $ reverse $ Qualifier an x : rest
monadReturn _ = Nothing
monadJoin (Generator _ (view -> PVar_ p) x:Qualifier _ (view -> Var_ v):xs)
| p == v && v `notElem` varss xs
= Just $ Qualifier an (rebracket1 $ App an (toNamed "join") x) : fromMaybe xs (monadJoin xs)
monadJoin (x:xs) = fmap (x:) $ monadJoin xs
monadJoin [] = Nothing
monadLet xs = if xs == ys then Nothing else Just ys
where
ys = map mkLet xs
vs = concatMap pvars [p | Generator _ p _ <- xs]
mkLet (Generator _ (view -> PVar_ p) (fromRet -> Just y))
| p `notElem` vars y, p `notElem` delete p vs
= LetStmt an $ BDecls an [PatBind an (toNamed p) Nothing (UnGuardedRhs an y) Nothing]
mkLet x = x
fromRet (Paren _ x) = fromRet x
fromRet (InfixApp _ x y z) | opExp y ~= "$" = fromRet $ App an x z
fromRet (App _ x y) | x ~= "return" = Just y
fromRet _ = Nothing
hlint-1.8.53/src/Hint/Match.hs 0000644 0000000 0000000 00000021657 12220306165 014205 0 ustar 00 0000000 0000000 {-# LANGUAGE PatternGuards, ViewPatterns, RelaxedPolyRec, RecordWildCards #-}
{-
The matching does a fairly simple unification between the two terms, treating
any single letter variable on the left as a free variable. After the matching
we substitute, transform and check the side conditions. We also "see through"
both ($) and (.) functions on the right.
TRANSFORM PATTERNS
_eval_ - perform deep evaluation, must be used at the top of a RHS
_noParen_ - don't bracket this particular item
SIDE CONDITIONS
(&&), (||), not - boolean connectives
isAtom x - does x never need brackets
isFoo x - is the root constructor of x a "Foo"
notEq x y - are x and y not equal
notIn xs ys - are all x variables not in ys expressions
notTypeSafe - no semantics, a hint for testing only
($) AND (.)
We see through ($)/(.) by expanding it if nothing else matches.
We also see through (.) by translating rules that have (.) equivalents
to separate rules. For example:
concat (map f x) ==> concatMap f x
-- we spot both these rules can eta reduce with respect to x
concat . map f ==> concatMap f
-- we use the associativity of (.) to add
concat . map f . x ==> concatMap f . x
-- currently 36 of 169 rules have (.) equivalents
-}
module Hint.Match(readMatch) where
import Data.List
import Data.Maybe
import Data.Data
import Unsafe.Coerce
import Settings
import Hint.Type
import Control.Monad
import Control.Arrow
import Util
import qualified Data.Set as Set
fmapAn = fmap (const an)
---------------------------------------------------------------------
-- READ THE RULE
readMatch :: [Setting] -> DeclHint
readMatch settings = findIdeas (concatMap readRule settings)
readRule :: Setting -> [Setting]
readRule m@MatchExp{lhs=(fmapAn -> lhs), rhs=(fmapAn -> rhs), side=(fmap fmapAn -> side)} =
(:) m{lhs=lhs,side=side,rhs=rhs} $ fromMaybe [] $ do
(l,v1) <- dotVersion lhs
(r,v2) <- dotVersion rhs
guard $ v1 == v2 && l /= [] && r /= [] && Set.notMember v1 (freeVars $ maybeToList side ++ l ++ r)
return [m{lhs=dotApps l, rhs=dotApps r, side=side}
,m{lhs=dotApps (l++[toNamed v1]), rhs=dotApps (r++[toNamed v1]), side=side}]
readRule _ = []
-- find a dot version of this rule, return the sequence of app prefixes, and the var
dotVersion :: Exp_ -> Maybe ([Exp_], String)
dotVersion (view -> Var_ v) | isUnifyVar v = Just ([], v)
dotVersion (fromApps -> xs) | length xs > 1 = fmap (first (apps (init xs) :)) $ dotVersion (fromParen $ last xs)
dotVersion _ = Nothing
---------------------------------------------------------------------
-- PERFORM THE MATCHING
findIdeas :: [Setting] -> Scope -> Module S -> Decl_ -> [Idea]
findIdeas matches s _ decl =
[ (idea (severityS m) (hintS m) x y){note=notes}
| decl <- case decl of InstDecl{} -> children decl; _ -> [decl]
, (parent,x) <- universeParentExp decl, not $ isParen x, let x2 = fmapAn x
, m <- matches, Just (y,notes) <- [matchIdea s decl m parent x2]]
matchIdea :: Scope -> Decl_ -> Setting -> Maybe (Int, Exp_) -> Exp_ -> Maybe (Exp_,[Note])
matchIdea s decl MatchExp{..} parent x = do
let nm = nameMatch scope s
u <- unifyExp nm True lhs x
u <- check u
let e = subst u rhs
let res = addBracket parent $ unqualify scope s u $ performEval e
guard $ (freeVars e Set.\\ freeVars rhs) `Set.isSubsetOf` freeVars x -- check no unexpected new free variables
guard $ checkSide side $ ("original",x) : ("result",res) : u
guard $ checkDefine decl parent res
return (res,notes)
---------------------------------------------------------------------
-- UNIFICATION
-- unify a b = c, a[c] = b
unify :: Data a => NameMatch -> Bool -> a -> a -> Maybe [(String,Exp_)]
unify nm root x y | Just x <- cast x = unifyExp nm root x (unsafeCoerce y)
| Just x <- cast x = unifyPat nm x (unsafeCoerce y)
| otherwise = unifyDef nm x y
unifyDef :: Data a => NameMatch -> a -> a -> Maybe [(String,Exp_)]
unifyDef nm x y = fmap concat . sequence =<< gzip (unify nm False) x y
-- App/InfixApp are analysed specially for performance reasons
-- root = True, this is the outside of the expr
-- do not expand out a dot at the root, since otherwise you get two matches because of readRule (Bug #570)
unifyExp :: NameMatch -> Bool -> Exp_ -> Exp_ -> Maybe [(String,Exp_)]
unifyExp nm root x y | isParen x || isParen y = unifyExp nm root (fromParen x) (fromParen y)
unifyExp nm root (Var _ (fromNamed -> v)) y | isUnifyVar v = Just [(v,y)]
unifyExp nm root (Var _ (Qual _ (ModuleName _ [m]) x)) (Var _ y)
| Qual _ (ModuleName _ m2) y <- y, y == x = Just [([m], Var an $ UnQual an $ Ident an m2)]
| UnQual _ y <- y, y == x = Just [([m], Var an $ UnQual an $ Ident an "")]
unifyExp nm root (Var _ x) (Var _ y) | nm x y = Just []
unifyExp nm root x@(App _ x1 x2) (App _ y1 y2) =
liftM2 (++) (unifyExp nm False x1 y1) (unifyExp nm False x2 y2) `mplus`
(do guard $ not root; InfixApp _ y11 dot y12 <- return $ fromParen y1; guard $ isDot dot; unifyExp nm root x (App an y11 (App an y12 y2)))
unifyExp nm root x (InfixApp _ lhs2 op2 rhs2)
| InfixApp _ lhs1 op1 rhs1 <- x = guard (op1 == op2) >> liftM2 (++) (unifyExp nm False lhs1 lhs2) (unifyExp nm False rhs1 rhs2)
| isDol op2 = unifyExp nm root x $ App an lhs2 rhs2
| otherwise = unifyExp nm root x $ App an (App an (opExp op2) lhs2) rhs2
unifyExp nm root x y | isOther x, isOther y = unifyDef nm x y
unifyExp nm root _ _ = Nothing
unifyPat :: NameMatch -> Pat_ -> Pat_ -> Maybe [(String,Exp_)]
unifyPat nm (PVar _ x) (PVar _ y) = Just [(fromNamed x, toNamed $ fromNamed y)]
unifyPat nm (PVar _ x) PWildCard{} = Just [(fromNamed x, toNamed $ "_" ++ fromNamed x)]
unifyPat nm x y = unifyDef nm x y
-- types that are not already handled in unify
{-# INLINE isOther #-}
isOther Var{} = False
isOther App{} = False
isOther InfixApp{} = False
isOther _ = True
---------------------------------------------------------------------
-- SUBSTITUTION UTILITIES
-- check the unification is valid
check :: [(String,Exp_)] -> Maybe [(String,Exp_)]
check = mapM f . groupSortFst
where f (x,ys) = if length (nub ys) == 1 then Just (x,head ys) else Nothing
-- perform a substitution
subst :: [(String,Exp_)] -> Exp_ -> Exp_
subst bind = transform g . transformBracket f
where
f (Var _ (fromNamed -> x)) | isUnifyVar x = lookup x bind
f _ = Nothing
g (App _ np x) | np ~= "_noParen_" = fromParen x
g x = x
---------------------------------------------------------------------
-- SIDE CONDITIONS
checkSide :: Maybe Exp_ -> [(String,Exp_)] -> Bool
checkSide x bind = maybe True f x
where
f (InfixApp _ x op y)
| opExp op ~= "&&" = f x && f y
| opExp op ~= "||" = f x || f y
f (App _ x y) | x ~= "not" = not $ f y
f (Paren _ x) = f x
f (App _ cond (sub -> y))
| 'i':'s':typ <- fromNamed cond
= isType typ y
f (App _ (App _ cond (sub -> x)) (sub -> y))
| cond ~= "notIn" = and [x `notElem` universe y | x <- list x, y <- list y]
| cond ~= "notEq" = x /= y
f x | x ~= "notTypeSafe" = True
f x = error $ "Hint.Match.checkSide, unknown side condition: " ++ prettyPrint x
isType "Atom" x = isAtom x
isType "WHNF" x = isWHNF x
isType "Nat" (asInt -> Just x) | x >= 0 = True
isType "Pos" (asInt -> Just x) | x > 0 = True
isType "Neg" (asInt -> Just x) | x < 0 = True
isType "NegZero" (asInt -> Just x) | x <= 0 = True
isType ('L':'i':'t':typ@(_:_)) (Lit _ x) = head (words $ show x) == typ
isType typ x = head (words $ show x) == typ
asInt :: Exp_ -> Maybe Integer
asInt (Paren _ x) = asInt x
asInt (NegApp _ x) = fmap negate $ asInt x
asInt (Lit _ (Int _ x _)) = Just x
asInt _ = Nothing
list :: Exp_ -> [Exp_]
list (List _ xs) = xs
list x = [x]
sub :: Exp_ -> Exp_
sub = transform f
where f (view -> Var_ x) | Just y <- lookup x bind = y
f x = x
-- does the result look very much like the declaration
checkDefine :: Decl_ -> Maybe (Int, Exp_) -> Exp_ -> Bool
checkDefine x Nothing y = fromNamed x /= fromNamed (transformBi unqual $ head $ fromApps y)
checkDefine _ _ _ = True
---------------------------------------------------------------------
-- TRANSFORMATION
-- if it has _eval_ do evaluation on it
performEval :: Exp_ -> Exp_
performEval (App _ e x) | e ~= "_eval_" = evaluate x
performEval x = x
-- contract Data.List.foo ==> foo, if Data.List is loaded
-- change X.foo => Module.foo, where X is looked up in the subst
unqualify :: Scope -> Scope -> [(String,Exp_)] -> Exp_ -> Exp_
unqualify from to subs = transformBi f
where
f (Qual _ (ModuleName _ [m]) x) | Just y <- fmap fromNamed $ lookup [m] subs
= if null y then UnQual an x else Qual an (ModuleName an y) x
f x = nameQualify from to x
addBracket :: Maybe (Int,Exp_) -> Exp_ -> Exp_
addBracket (Just (i,p)) c | needBracket i p c = Paren an c
addBracket _ x = x
hlint-1.8.53/src/Hint/ListRec.hs 0000644 0000000 0000000 00000013247 12220306165 014512 0 ustar 00 0000000 0000000 {-# LANGUAGE PatternGuards, ViewPatterns #-}
{-
map f [] = []
map f (x:xs) = f x : map f xs
foldr f z [] = z
foldr f z (x:xs) = f x (foldr f z xs)
foldl f z [] = z
foldl f z (x:xs) = foldl f (f z x) xs
-}
{-
f (x:xs) = negate x + f xs ; f [] = 0 -- f xs = foldr ((+) . negate) 0 xs
f (x:xs) = x + 1 : f xs ; f [] = [] -- f xs = map (+ 1) xs
f z (x:xs) = f (z*x) xs ; f z [] = z -- f z xs = foldl (*) z xs
f a (x:xs) b = x + a + b : f a xs b ; f a [] b = [] -- f a xs b = map (\ x -> x + a + b) xs
f [] a = return a ; f (x:xs) a = a + x >>= \fax -> f xs fax -- f xs a = foldM (+) a xs
foos [] x = x; foos (y:ys) x = foo y $ foos ys x -- foos ys x = foldr foo x ys
f [] y = y; f (x:xs) y = f xs $ g x y -- f xs y = foldl (flip g) y xs
f [] y = y; f (x : xs) y = let z = g x y in f xs z -- f xs y = foldl (flip g) y xs
f [] y = y; f (x:xs) y = f xs (f xs z)
-}
module Hint.ListRec(listRecHint) where
import Hint.Type
import Util
import Hint.Util
import Data.List
import Data.Maybe
import Data.Ord
import Data.Either
import Control.Monad
listRecHint :: DeclHint
listRecHint _ _ = concatMap f . universe
where
f o = maybeToList $ do
let x = o
(x, addCase) <- findCase x
(use,severity,x) <- matchListRec x
let y = addCase x
guard $ recursiveStr `notElem` varss y
return $ idea severity ("Use " ++ use) o y
recursiveStr = "_recursive_"
recursive = toNamed recursiveStr
-- recursion parameters, nil-case, (x,xs,cons-case)
-- for cons-case delete any recursive calls with xs from them
-- any recursive calls are marked "_recursive_"
data ListCase = ListCase [String] Exp_ (String,String,Exp_)
deriving Show
data BList = BNil | BCons String String
deriving (Eq,Ord,Show)
-- function name, parameters, list-position, list-type, body (unmodified)
data Branch = Branch String [String] Int BList Exp_
deriving Show
---------------------------------------------------------------------
-- MATCH THE RECURSION
matchListRec :: ListCase -> Maybe (String,Severity,Exp_)
matchListRec o@(ListCase vs nil (x,xs,cons))
| [] <- vs, nil ~= "[]", InfixApp _ lhs c rhs <- cons, opExp c ~= ":"
, fromParen rhs =~= recursive, xs `notElem` vars lhs
= Just $ (,,) "map" Error $ appsBracket
[toNamed "map", niceLambda [x] lhs, toNamed xs]
| [] <- vs, App2 op lhs rhs <- view cons
, vars op `disjoint` [x,xs]
, fromParen rhs == recursive, xs `notElem` vars lhs
= Just $ (,,) "foldr" Warning $ appsBracket
[toNamed "foldr", niceLambda [x] $ appsBracket [op,lhs], nil, toNamed xs]
| [v] <- vs, view nil == Var_ v, App _ r lhs <- cons, r =~= recursive
, xs `notElem` vars lhs
= Just $ (,,) "foldl" Warning $ appsBracket
[toNamed "foldl", niceLambda [v,x] lhs, toNamed v, toNamed xs]
| [v] <- vs, App _ ret res <- nil, ret ~= "return", res ~= "()" || view res == Var_ v
, [Generator _ (view -> PVar_ b1) e, Qualifier _ (fromParen -> App _ r (view -> Var_ b2))] <- asDo cons
, b1 == b2, r == recursive, xs `notElem` vars e
, name <- "foldM" ++ ['_'|res ~= "()"]
= Just $ (,,) name Warning $ appsBracket
[toNamed name, niceLambda [v,x] e, toNamed v, toNamed xs]
| otherwise = Nothing
-- Very limited attempt to convert >>= to do, only useful for foldM/foldM_
asDo :: Exp_ -> [Stmt S]
asDo (view -> App2 bind lhs (Lambda _ [v] rhs)) = [Generator an v lhs, Qualifier an rhs]
asDo (Do _ x) = x
asDo x = [Qualifier an x]
---------------------------------------------------------------------
-- FIND THE CASE ANALYSIS
findCase :: Decl_ -> Maybe (ListCase, Exp_ -> Decl_)
findCase x = do
FunBind _ [x1,x2] <- return x
Branch name1 ps1 p1 c1 b1 <- findBranch x1
Branch name2 ps2 p2 c2 b2 <- findBranch x2
guard (name1 == name2 && ps1 == ps2 && p1 == p2)
[(BNil, b1), (BCons x xs, b2)] <- return $ sortBy (comparing fst) [(c1,b1), (c2,b2)]
b2 <- transformAppsM (delCons name1 p1 xs) b2
(ps,b2) <- return $ eliminateArgs ps1 b2
let ps12 = let (a,b) = splitAt p1 ps1 in map toNamed $ a ++ xs : b
return (ListCase ps b1 (x,xs,b2)
,\e -> FunBind an [Match an (toNamed name1) ps12 (UnGuardedRhs an e) Nothing])
delCons :: String -> Int -> String -> Exp_ -> Maybe Exp_
delCons func pos var (fromApps -> (view -> Var_ x):xs) | func == x = do
(pre, (view -> Var_ v):post) <- return $ splitAt pos xs
guard $ v == var
return $ apps $ recursive : pre ++ post
delCons _ _ _ x = return x
eliminateArgs :: [String] -> Exp_ -> ([String], Exp_)
eliminateArgs ps cons = (remove ps, transform f cons)
where
args = [zs | z:zs <- map fromApps $ universeApps cons, z =~= recursive]
elim = [all (\xs -> length xs > i && view (xs !! i) == Var_ p) args | (i,p) <- zip [0..] ps] ++ repeat False
remove = concat . zipWith (\b x -> [x | not b]) elim
f (fromApps -> x:xs) | x == recursive = apps $ x : remove xs
f x = x
---------------------------------------------------------------------
-- FIND A BRANCH
findBranch :: Match S -> Maybe Branch
findBranch x = do
Match _ name ps (UnGuardedRhs _ bod) Nothing <- return x
(a,b,c) <- findPat ps
return $ Branch (fromNamed name) a b c $ simplifyExp bod
findPat :: [Pat_] -> Maybe ([String], Int, BList)
findPat ps = do
ps <- mapM readPat ps
[i] <- return $ findIndices isRight_ ps
let (left,[right]) = partitionEithers ps
return (left, i, right)
readPat :: Pat_ -> Maybe (Either String BList)
readPat (view -> PVar_ x) = Just $ Left x
readPat (PParen _ (PInfixApp _ (view -> PVar_ x) (Special _ Cons{}) (view -> PVar_ xs))) = Just $ Right $ BCons x xs
readPat (PList _ []) = Just $ Right BNil
readPat _ = Nothing
hlint-1.8.53/src/Hint/List.hs 0000644 0000000 0000000 00000004637 12220306165 014063 0 ustar 00 0000000 0000000 {-# LANGUAGE ViewPatterns, PatternGuards #-}
{-
Find and match:
yes = 1:2:[] -- [1,2]
yes = ['h','e','l','l','o'] -- "hello"
-- [a]++b -> a : b, but only if not in a chain of ++'s
yes = [x] ++ xs -- x : xs
yes = "x" ++ xs -- 'x' : xs
no = [x] ++ xs ++ ys
no = xs ++ [x] ++ ys
yes = [if a then b else c] ++ xs -- (if a then b else c) : xs
yes = [1] : [2] : [3] : [4] : [5] : [] -- [[1], [2], [3], [4], [5]]
yes = if x == e then l2 ++ xs else [x] ++ check_elem xs -- x : check_elem xs
data Yes = Yes (Maybe [Char]) -- Maybe String
yes = y :: [Char] -> a -- String -> a
instance C [Char]
foo = [a b] ++ xs -- a b : xs
-}
module Hint.List where
import Hint.Type
listHint :: DeclHint
listHint _ _ = listDecl
listDecl :: Decl_ -> [Idea]
listDecl x = concatMap (listExp False) (childrenBi x) ++ stringType x
-- boolean = are you in a ++ chain
listExp :: Bool -> Exp_ -> [Idea]
listExp b (fromParen -> x) =
if null res then concatMap (listExp $ isAppend x) $ children x else [head res]
where
res = [warn name x x2 | (name,f) <- checks, Just x2 <- [f b x]]
isAppend (view -> App2 op _ _) = op ~= "++"
isAppend _ = False
checks = let (*) = (,) in
["Use string literal" * useString
,"Use list literal" * useList
,"Use :" * useCons
]
useString b (List _ xs) | xs /= [] && all isChar xs = Just $ Lit an $ String an s (show s)
where s = map fromChar xs
useString b _ = Nothing
useList b = fmap (List an) . f True
where
f first x | x ~= "[]" = if first then Nothing else Just []
f first (view -> App2 c a b) | c ~= ":" = fmap (a:) $ f False b
f first _ = Nothing
useCons False (view -> App2 op x y) | op ~= "++", Just x2 <- f x, not $ isAppend y =
Just $ InfixApp an x2 (QConOp an $ list_cons_name an) y
where
f (Lit _ (String _ [x] _)) = Just $ Lit an $ Char an x (show x)
f (List _ [x]) = Just $ if isApp x then x else paren x
f _ = Nothing
useCons _ _ = Nothing
typeListChar = TyList an (TyCon an (toNamed "Char"))
typeString = TyCon an (toNamed "String")
stringType :: Decl_ -> [Idea]
stringType x = case x of
InstDecl _ _ _ x -> f x
_ -> f x
where
f x = concatMap g $ childrenBi x
g :: Type_ -> [Idea]
g (fromTyParen -> x) = [warn "Use String" x (transform f x) | any (=~= typeListChar) $ universe x]
where f x = if x =~= typeListChar then typeString else x
hlint-1.8.53/src/Hint/Lambda.hs 0000644 0000000 0000000 00000010543 12220306165 014321 0 ustar 00 0000000 0000000 {-# LANGUAGE ViewPatterns, PatternGuards #-}
{-
Concept:
Remove all the lambdas you can be inserting only sections
Never create a right section with +-# as the operator (they are misparsed)
Rules:
fun a = \x -> y -- promote lambdas, provided no where's outside the lambda
fun x = y x -- eta reduce, x /= mr and foo /= symbol
\x -> y x -- eta reduce
((#) x) ==> (x #) -- rotate operators
(flip op x) ==> (`op` x) -- rotate operators
\x y -> x + y ==> (+) -- insert operator
\x y -> op y x ==> flip op
\x -> x + y ==> (+ y) -- insert section,
\x -> op x y ==> (`op` y) -- insert section
\x -> y + x ==> (y +) -- insert section
\x -> \y -> ... ==> \x y -- lambda compression
\x -> (x +) ==> (+) -- operator reduction
f a = \x -> x + x -- f a x = x + x
f a = \a -> a + a -- f _ a = a + a
f a = \x -> x + x where _ = test
f = \x -> x + x -- f x = x + x
fun x y z = f x y z -- fun = f
fun x y z = f x x y z -- fun x = f x x
fun x y z = f g z -- fun x y = f g
fun mr = y mr
f = foo ((*) x) -- (x *)
f = (*) x
f = foo (flip op x) -- (`op` x)
f = flip op x
f = foo (flip (*) x) -- (* x)
f = foo (flip (-) x)
f = foo (\x y -> fun x y) -- @Error fun
f = foo (\x y -> x + y) -- (+)
f = foo (\x -> x * y) -- @Warning (* y)
f = foo (\x -> x # y)
f = foo (\x -> \y -> x x y y) -- \x y -> x x y y
f = foo (\x -> \x -> foo x x) -- \_ x -> foo x x
f = foo (\(x:xs) -> \x -> foo x x) -- \(_:xs) x -> foo x x
f = foo (\x -> \y -> \z -> x x y y z z) -- \x y z -> x x y y z z
x ! y = fromJust $ lookup x y
f = foo (\i -> writeIdea (getClass i) i)
f = bar (flip Foo.bar x) -- (`Foo.bar` x)
f = a b (\x -> c x d) -- (`c` d)
yes = \x -> a x where -- a
yes = \x y -> op y x where -- flip op
f = \y -> nub $ reverse y where -- nub . reverse
f = \z -> foo $ bar $ baz z where -- foo . bar . baz
f = \z -> foo $ bar x $ baz z where -- foo . bar x . baz
f = \z -> foo $ z $ baz z where
f = \x -> bar map (filter x) where -- bar map . filter
f = bar &+& \x -> f (g x)
foo = [\column -> set column [treeViewColumnTitle := printf "%s (match %d)" name (length candidnates)]]
foo = [\x -> x]
foo = [\m x -> insert x x m]
foo a b c = bar (flux ++ quux) c where flux = a -- foo a b = bar (flux ++ quux)
foo a b c = bar (flux ++ quux) c where flux = c
yes = foo (\x -> Just x) -- @Error Just
foo = bar (\x -> (x `f`)) -- f
baz = bar (\x -> (x +)) -- (+)
-}
module Hint.Lambda 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 _ _ = []
-- replace any repeated pattern variable with _
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)
hlint-1.8.53/src/Hint/Import.hs 0000644 0000000 0000000 00000013754 12220306165 014422 0 ustar 00 0000000 0000000 {-# LANGUAGE PatternGuards, ScopedTypeVariables, RecordWildCards #-}
{-
Reduce the number of import declarations.
Two import declarations can be combined if:
(note, A[] is A with whatever import list, or none)
import A[]; import A[] = import A[]
import A(B); import A(C) = import A(B,C)
import A; import A(C) = import A
import A; import A hiding (C) = import A
import A[]; import A[] as Y = import A[] as Y
import A; import A -- import A
import A; import A; import A -- import A
import A(Foo) ; import A -- import A
import A(Bar(..)); import {-# SOURCE #-} A
import A; import B
import A(B) ; import A(C) -- import A(B,C)
import A; import A hiding (C) -- import A
import A; import A as Y -- import A as Y
import A; import qualified A as Y
import A as B; import A as C
import A as A -- import A
import qualified A as A -- import qualified A
import A; import B; import A -- import A
import qualified A; import A
import B; import A; import A -- import A
import A hiding(Foo); import A hiding(Bar)
import List -- import Data.List
import qualified List -- import qualified Data.List as List
import Char(foo) -- import Data.Char(foo)
import IO(foo)
import IO as X -- import System.IO as X; import System.IO.Error as X; import Control.Exception as X (bracket,bracket_)
module Foo(module A, baz, module B, module C) where; import A; import D; import B(map,filter); import C \
-- module Foo(baz, module X) where; import A as X; import B as X(map, filter); import C as X
module Foo(module A, baz, module B, module X) where; import A; import B; import X \
-- module Foo(baz, module Y) where; import A as Y; import B as Y; import X as Y
-}
module Hint.Import where
import Hint.Type
import Util
import Data.List
import Data.Maybe
importHint :: ModuHint
importHint _ x = concatMap (wrap . snd) (groupSortFst
[((fromNamed $ importModule i,importPkg i),i) | i <- universeBi x, not $ importSrc i]) ++
concatMap (\x -> hierarchy x ++ reduce1 x) (universeBi x) ++
multiExport x
wrap :: [ImportDecl S] -> [Idea]
wrap o = [ rawIdea Error "Use fewer imports" (toSrcLoc $ ann $ head o) (f o) (f x) []
| Just x <- [simplify o]]
where f = unlines . map prettyPrint
simplify :: [ImportDecl S] -> Maybe [ImportDecl S]
simplify [] = Nothing
simplify (x:xs) = case simplifyHead x xs of
Nothing -> fmap (x:) $ simplify xs
Just xs -> Just $ fromMaybe xs $ simplify xs
simplifyHead :: ImportDecl S -> [ImportDecl S] -> Maybe [ImportDecl S]
simplifyHead x [] = Nothing
simplifyHead x (y:ys) = case reduce x y of
Nothing -> fmap (y:) $ simplifyHead x ys
Just xy -> Just $ xy : ys
reduce :: ImportDecl S -> ImportDecl S -> Maybe (ImportDecl S)
reduce x y | qual, as, specs = Just x
| qual, as, Just (ImportSpecList _ False xs) <- importSpecs x, Just (ImportSpecList _ False ys) <- importSpecs y =
Just x{importSpecs = Just $ ImportSpecList an False $ nub_ $ xs ++ ys}
| qual, as, isNothing (importSpecs x) || isNothing (importSpecs y) = Just x{importSpecs=Nothing}
| not (importQualified x), qual, specs, length ass == 1 = Just x{importAs=Just $ head ass}
where
qual = importQualified x == importQualified y
as = importAs x `eqMaybe` importAs y
ass = mapMaybe importAs [x,y]
specs = importSpecs x `eqMaybe` importSpecs y
reduce _ _ = Nothing
reduce1 :: ImportDecl S -> [Idea]
reduce1 i@ImportDecl{..}
| Just (dropAnn importModule) == fmap dropAnn importAs
= [warn "Redundant as" i i{importAs=Nothing}]
reduce1 _ = []
newNames = let (*) = flip (,) in
["Control" * "Monad"
,"Data" * "Char"
,"Data" * "List"
,"Data" * "Maybe"
,"Data" * "Ratio"
,"System" * "Directory"
-- Special, see bug #393
-- ,"System" * "IO"
-- Do not encourage use of old-locale/old-time over haskell98
-- ,"System" * "Locale"
-- ,"System" * "Time"
]
hierarchy :: ImportDecl S -> [Idea]
hierarchy i@ImportDecl{importModule=ModuleName _ x,importPkg=Nothing} | Just y <- lookup x newNames
= [warn "Use hierarchical imports" i (desugarQual i){importModule=ModuleName an $ y ++ "." ++ x}]
-- import IO is equivalent to
-- import System.IO, import System.IO.Error, import Control.Exception(bracket, bracket_)
hierarchy i@ImportDecl{importModule=ModuleName _ "IO", importSpecs=Nothing,importPkg=Nothing}
= [rawIdea Warning "Use hierarchical imports" (toSrcLoc $ ann i) (ltrim $ prettyPrint i) (
unlines $ map (ltrim . prettyPrint)
[f "System.IO" Nothing, f "System.IO.Error" Nothing
,f "Control.Exception" $ Just $ ImportSpecList an False [IVar an $ toNamed x | x <- ["bracket","bracket_"]]]) []]
where f a b = (desugarQual i){importModule=ModuleName an a, importSpecs=b}
hierarchy _ = []
-- import qualified X ==> import qualified X as X
desugarQual :: ImportDecl S -> ImportDecl S
desugarQual x | importQualified x && isNothing (importAs x) = x{importAs=Just (importModule x)}
| otherwise = x
multiExport :: Module S -> [Idea]
multiExport x =
[ rawIdea Warning "Use import/export shortcut" (toSrcLoc $ ann hd)
(unlines $ prettyPrint hd : map prettyPrint imps)
(unlines $ prettyPrint newhd : map prettyPrint newimps)
[]
| Module l (Just hd) _ imp _ <- [x]
, let asNames = mapMaybe importAs imp
, let expNames = [x | EModuleContents _ x <- childrenBi hd]
, let imps = [i | i@ImportDecl{importAs=Nothing,importQualified=False,importModule=name} <- imp
,name `notElem_` asNames, name `elem_` expNames]
, length imps >= 3
, let newname = ModuleName an $ head $ map return ("XYZ" ++ ['A'..]) \\
[x | ModuleName (_ :: S) x <- universeBi hd ++ universeBi imp]
, let reexport (EModuleContents _ x) = x `notElem_` map importModule imps
reexport x = True
, let newhd = descendBi (\xs -> filter reexport xs ++ [EModuleContents an newname]) hd
, let newimps = [i{importAs=Just newname} | i <- imps]
]
hlint-1.8.53/src/Hint/Extensions.hs 0000644 0000000 0000000 00000015445 12220306165 015306 0 ustar 00 0000000 0000000 {-
Suggest removal of unnecessary extensions
i.e. They have {-# LANGUAGE RecursiveDo #-} but no mdo keywords
{-# LANGUAGE Arrows #-} \
f = id --
{-# LANGUAGE TotallyUnknown #-} \
f = id
{-# LANGUAGE Foo, Generics, ParallelListComp, ImplicitParams #-} \
f = [(a,c) | a <- b | c <- d] -- {-# LANGUAGE Foo, ParallelListComp #-}
{-# LANGUAGE EmptyDataDecls #-} \
data Foo
{-# LANGUAGE TemplateHaskell #-} \
$(deriveNewtypes typeInfo)
{-# LANGUAGE TemplateHaskell #-} \
main = foo ''Bar
{-# LANGUAGE PatternGuards #-} \
test = case x of _ | y <- z -> w
{-# LANGUAGE TemplateHaskell,EmptyDataDecls #-} \
$(fmap return $ dataD (return []) (mkName "Void") [] [] [])
{-# LANGUAGE RecursiveDo #-} \
main = mdo x <- y; return y
{-# LANGUAGE ImplicitParams, BangPatterns #-} \
sort :: (?cmp :: a -> a -> Bool) => [a] -> [a] \
sort !f = undefined
{-# LANGUAGE KindSignatures #-} \
data Set (cxt :: * -> *) a = Set [a]
{-# LANGUAGE RecordWildCards #-} \
record field = Record{..}
{-# LANGUAGE RecordWildCards #-} \
record = 1 --
{-# LANGUAGE UnboxedTuples #-} \
record = 1 --
{-# LANGUAGE TemplateHaskell #-} \
foo
{-# LANGUAGE GeneralizedNewtypeDeriving, DeriveDataTypeable #-} \
record = 1 --
{-# LANGUAGE GeneralizedNewtypeDeriving, DeriveDataTypeable #-} \
newtype Foo = Foo Int deriving Data -- {-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE GeneralizedNewtypeDeriving, DeriveDataTypeable #-} \
data Foo = Foo Int deriving Data -- {-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE GeneralizedNewtypeDeriving, DeriveDataTypeable #-} \
newtype Foo = Foo Int deriving Class -- {-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE GeneralizedNewtypeDeriving, DeriveDataTypeable #-} \
data Foo = Foo Int deriving Class --
{-# LANGUAGE DeriveFunctor #-} \
data Foo = Foo Int deriving Functor
{-# LANGUAGE DeriveFunctor #-} \
newtype Foo = Foo Int deriving Functor --
{-# LANGUAGE DeriveFunctor, GeneralizedNewtypeDeriving, StandaloneDeriving #-} \
deriving instance Functor Bar
{-# LANGUAGE DeriveFunctor, GeneralizedNewtypeDeriving, StandaloneDeriving #-} \
deriving instance Show Bar -- {-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE DeriveGeneric, GeneralizedNewtypeDeriving #-} \
newtype Micro = Micro Int deriving Generic -- {-# LANGUAGE DeriveGeneric #-}
-}
module Hint.Extensions where
import Hint.Type
import Data.Maybe
import Data.List
import Util
extensionsHint :: ModuHint
extensionsHint _ x = [rawIdea Error "Unused LANGUAGE pragma" (toSrcLoc sl)
(prettyPrint o) (if null new then "" else prettyPrint $ LanguagePragma sl $ map (toNamed . prettyExtension) new)
(warnings old new)
| not $ used TemplateHaskell x -- if TH is on, can use all other extensions programmatically
, o@(LanguagePragma sl exts) <- modulePragmas x
, let old = map (parseExtension . prettyPrint) exts
, let new = minimalExtensions x old
, sort new /= sort old]
minimalExtensions :: Module_ -> [Extension] -> [Extension]
minimalExtensions x es = nub $ concatMap f es
where f e = [e | usedExt e x]
-- RecordWildCards implies DisambiguateRecordFields, but most people probably don't want it
warnings old new | wildcards `elem` old && wildcards `notElem` new = [Note "you may need to add DisambiguateRecordFields"]
where wildcards = EnableExtension RecordWildCards
warnings _ _ = []
usedExt :: Extension -> Module_ -> Bool
usedExt (UnknownExtension "DeriveGeneric") = hasDerive True ["Generic","Generic1"]
usedExt (EnableExtension x) = used x
usedExt _ = const True
used :: KnownExtension -> Module_ -> Bool
used RecursiveDo = hasS isMDo
used ParallelListComp = hasS isParComp
used FunctionalDependencies = hasT (un :: FunDep S)
used ImplicitParams = hasT (un :: IPName S)
used EmptyDataDecls = hasS f
where f (DataDecl _ _ _ _ [] _) = True
f (GDataDecl _ _ _ _ _ [] _) = True
f _ = False
used KindSignatures = hasT (un :: Kind S)
used BangPatterns = hasS isPBangPat
used TemplateHaskell = hasT2 (un :: (Bracket S, Splice S)) & hasS f & hasS isSpliceDecl
where f VarQuote{} = True
f TypQuote{} = True
f _ = False
used ForeignFunctionInterface = hasT (un :: CallConv S)
used Generics = hasS isPExplTypeArg
used PatternGuards = hasS f1 & hasS f2
where f1 (GuardedRhs _ xs _) = g xs
f2 (GuardedAlt _ xs _) = g xs
g [] = False
g [Qualifier{}] = False
g _ = True
used StandaloneDeriving = hasS isDerivDecl
used PatternSignatures = hasS isPatTypeSig
used RecordWildCards = hasS isPFieldWildcard & hasS isFieldWildcard
used RecordPuns = hasS isPFieldPun & hasS isFieldPun
used UnboxedTuples = has isBoxed
used PackageImports = hasS (isJust . importPkg)
used QuasiQuotes = hasS isQuasiQuote
used ViewPatterns = hasS isPViewPat
used DeriveDataTypeable = hasDerive True ["Data","Typeable"]
used DeriveFunctor = hasDerive False ["Functor"]
used DeriveFoldable = hasDerive False ["Foldable"]
used DeriveTraversable = hasDerive False ["Traversable"]
used GeneralizedNewtypeDeriving = not . null . filter (`notElem` special) . fst . derives
where special = ["Read","Show","Data","Typeable","Generic","Generic1"] -- these classes cannot use generalised deriving
-- FIXME: This special list is duplicated here, and as booleans to hasDerive
used Arrows = hasS f
where f Proc{} = True
f LeftArrApp{} = True
f RightArrApp{} = True
f LeftArrHighApp{} = True
f RightArrHighApp{} = True
f _ = False
used TransformListComp = hasS f
where f QualStmt{} = False
f _ = True
-- for forwards compatibility, if things ever get added to the extension enumeration
used x = usedExt $ UnknownExtension $ show x
hasDerive :: Bool -> [String] -> Module_ -> Bool
hasDerive nt want m = not $ null $ intersect want $ if nt then new ++ dat else dat
where (new,dat) = derives m
-- | What is derived on newtype, and on data type
-- 'deriving' declarations may be on either, so we approximate
derives :: Module_ -> ([String],[String])
derives = concatUnzip . map f . childrenBi
where
f :: Decl_ -> ([String], [String])
f (DataDecl _ dn _ _ _ ds) = g dn ds
f (GDataDecl _ dn _ _ _ _ ds) = g dn ds
f (DataInsDecl _ dn _ _ ds) = g dn ds
f (GDataInsDecl _ dn _ _ _ ds) = g dn ds
f (DerivDecl _ _ hd) = (xs, xs) -- don't know whether this was on newtype or not
where xs = [h hd]
f _ = ([], [])
g dn ds = if isNewType dn then (xs,[]) else ([],xs)
where xs = maybe [] (map h . fromDeriving) ds
h (IHead _ a _) = prettyPrint $ unqual a
h (IHInfix _ _ a _) = prettyPrint $ unqual a
h (IHParen _ a) = h a
un = undefined
(&) f g x = f x || g x
hasT t x = notNull (universeBi x `asTypeOf` [t])
hasT2 ~(t1,t2) = hasT t1 & hasT t2
hasS :: Biplate x (f S) => (f S -> Bool) -> x -> Bool
hasS test = any test . universeBi
has f = any f . universeBi
hlint-1.8.53/src/Hint/Duplicate.hs 0000644 0000000 0000000 00000005135 12220306165 015054 0 ustar 00 0000000 0000000 {-# LANGUAGE PatternGuards, ScopedTypeVariables #-}
{-
Find bindings within a let, and lists of statements
If you have n the same, error out
main = do a; a; a; a
main = do a; a; a; a; a; a -- ???
main = do a; a; a; a; a; a; a -- ???
main = do (do b; a; a; a); do (do c; a; a; a) -- ???
main = do a; a; a; b; a; a; a -- ???
main = do a; a; a; b; a; a
foo = a where {a = 1; b = 2; c = 3}; bar = a where {a = 1; b = 2; c = 3} -- ???
-}
module Hint.Duplicate(duplicateHint) where
import Hint.Type
import Control.Arrow
import Data.List hiding (find)
import qualified Data.Map as Map
duplicateHint :: CrossHint
duplicateHint ms =
dupes [y | Do _ y :: Exp S <- universeBi modu] ++
dupes [y | BDecls l y :: Binds S <- universeBi modu]
where modu = map snd ms
dupes ys =
[rawIdea
(if length xs >= 5 then Error else Warning)
"Reduce duplication" p1
(unlines $ map (prettyPrint . fmap (const p1)) xs)
("Combine with " ++ showSrcLoc p2) []
| (p1,p2,xs) <- duplicateOrdered 3 $ map (map (toSrcLoc . ann &&& dropAnn)) ys]
---------------------------------------------------------------------
-- DUPLICATE FINDING
-- | The position to return if we match at this point, and the map of where to go next
-- If two runs have the same vals, always use the first pos you find
data Dupe pos val = Dupe pos (Map.Map val (Dupe pos val))
find :: Ord val => [val] -> Dupe pos val -> (pos, Int)
find (v:vs) (Dupe p mp) | Just d <- Map.lookup v mp = second (+1) $ find vs d
find _ (Dupe p mp) = (p, 0)
add :: Ord val => pos -> [val] -> Dupe pos val -> Dupe pos val
add pos [] d = d
add pos (v:vs) (Dupe p mp) = Dupe p $ Map.insertWith f v (add pos vs $ Dupe pos Map.empty) mp
where f new old = add pos vs old
duplicateOrdered :: Ord val => Int -> [[(SrcLoc,val)]] -> [(SrcLoc,SrcLoc,[val])]
duplicateOrdered threshold xs = concat $ concat $ snd $ mapAccumL f (Dupe nullSrcLoc Map.empty) xs
where
f d xs = second overlaps $ mapAccumL (g pos) d $ takeWhile ((>= threshold) . length) $ tails xs
where pos = Map.fromList $ zip (map fst xs) [0..]
g pos d xs = (d2, res)
where
res = [(p,pme,take mx vs) | i >= threshold
,let mx = maybe i (\x -> min i $ (pos Map.! pme) - x) $ Map.lookup p pos
,mx >= threshold]
vs = map snd xs
(p,i) = find vs d
pme = fst $ head xs
d2 = add pme vs d
overlaps (x@((_,_,n):_):xs) = x : overlaps (drop (length n - 1) xs)
overlaps (x:xs) = x : overlaps xs
overlaps [] = []
hlint-1.8.53/src/Hint/Bracket.hs 0000644 0000000 0000000 00000010046 12220306165 014512 0 ustar 00 0000000 0000000 {-# LANGUAGE ViewPatterns #-}
{-
Raise an error if you are bracketing an atom, or are enclosed be a list bracket
-- expression bracket reduction
yes = (f x) x -- @Warning f x x
no = f (x x)
yes = (foo) -- foo
yes = (foo bar) -- @Warning foo bar
yes = foo (bar) -- @Error bar
yes = foo ((x x)) -- @Error (x x)
yes = (f x) ||| y -- @Warning f x ||| y
yes = if (f x) then y else z -- @Warning if f x then y else z
yes = if x then (f y) else z -- @Warning if x then f y else z
yes = (a foo) :: Int -- @Warning a foo :: Int
yes = [(foo bar)] -- @Warning [foo bar]
yes = foo ((x y), z) -- @Warning (x y, z)
yes = C { f = (e h) } -- @Warning C {f = e h}
yes = \ x -> (x && x) -- @Warning \x -> x && x
no = \(x -> y) -> z
yes = (`foo` (bar baz)) -- @Warning (`foo` bar baz)
main = do f; (print x) -- @Warning do f print x
-- type bracket reduction
foo :: (Int -> Int) -> Int
foo :: Int -> (Int -> Int) -- @Warning Int -> Int -> Int
foo :: (Maybe Int) -> a -- @Warning Maybe Int -> a
instance Named (DeclHead S)
data Foo = Foo {foo :: (Maybe Foo)} -- @Warning foo :: Maybe Foo
-- pattern bracket reduction
foo (True) = 1
foo ((True)) = 1 -- @Error True
-- dollar reduction tests
no = groupFsts . sortFst $ mr
yes = split "to" $ names -- split "to" names
yes = white $ keysymbol -- white keysymbol
yes = operator foo $ operator -- operator foo operator
no = operator foo $ operator bar
yes = return $ Record{a=b} -- return Record{a=b}
-- $/bracket rotation tests
yes = (b $ c d) ++ e -- b (c d) ++ e
yes = (a b $ c d) ++ e -- a b (c d) ++ e
no = (f . g $ a) ++ e
no = quickCheck ((\h -> cySucc h == succ h) :: Hygiene -> Bool)
foo = (case x of y -> z; q -> w) :: Int
-- backup fixity resolution
main = do a += b . c; return $ a . b
-- annotations
main = 1; {-# ANN module ("HLint: ignore Use camelCase" :: String) #-}
main = 1; {-# ANN module (1 + (2)) #-} -- 2
-}
module Hint.Bracket where
import Hint.Type
bracketHint :: DeclHint
bracketHint _ _ x =
concatMap (\x -> bracket True x ++ dollar x) (childrenBi (descendBi annotations x) :: [Exp_]) ++
concatMap (bracket False) (childrenBi x :: [Type_]) ++
concatMap (bracket False) (childrenBi x :: [Pat_]) ++
concatMap fieldDecl (childrenBi x)
where
-- Brackets at the roots of annotations are fine, so we strip them
annotations :: Annotation S -> Annotation S
annotations = descendBi $ \x -> case (x :: Exp_) of
Paren _ x -> x
x -> x
bracket :: (Annotated a, Uniplate (a S), ExactP a, Pretty (a S), Brackets (a S)) => Bool -> a S -> [Idea]
bracket bad = f Nothing
where
msg = "Redundant bracket"
-- f (Maybe (index, parent, gen)) child
f :: (Annotated a, Uniplate (a S), ExactP a, Pretty (a S), Brackets (a S)) => Maybe (Int,a S,a S -> a S) -> a S -> [Idea]
f Just{} o@(remParen -> Just x) | isAtom x = err msg o x : g x
f Nothing o@(remParen -> Just x) | bad = warn msg o x : g x
f (Just (i,o,gen)) (remParen -> Just x) | not $ needBracket i o x = warn msg o (gen x) : g x
f _ x = g x
g :: (Annotated a, Uniplate (a S), ExactP a, Pretty (a S), Brackets (a S)) => a S -> [Idea]
g o = concat [f (Just (i,o,gen)) x | (i,(x,gen)) <- zip [0..] $ holes o]
fieldDecl :: FieldDecl S -> [Idea]
fieldDecl o@(FieldDecl a b (UnBangedTy c (TyParen _ d)))
= [warn "Redundant bracket" o (FieldDecl a b (UnBangedTy c d))]
fieldDecl _ = []
dollar :: Exp_ -> [Idea]
dollar = concatMap f . universe
where
msg = warn "Redundant $"
f x = [msg x y | InfixApp _ a d b <- [x], opExp d ~= "$"
,let y = App an a b, not $ needBracket 0 y a, not $ needBracket 1 y b]
++
[msg x (t y) |(t, Paren _ (InfixApp _ a1 op1 a2)) <- splitInfix x
,opExp op1 ~= "$", isVar a1 || isApp a1 || isParen a1, not $ isAtom a2
,let y = App an a1 (Paren an a2)]
-- return both sides, and a way to put them together again
splitInfix :: Exp_ -> [(Exp_ -> Exp_, Exp_)]
splitInfix (InfixApp s a b c) = [(InfixApp s a b, c), (\a -> InfixApp s a b c, a)]
splitInfix _ = []
hlint-1.8.53/src/Hint/All.hs 0000644 0000000 0000000 00000001651 12220306165 013651 0 ustar 00 0000000 0000000
module Hint.All(
Hint(..), DeclHint, ModuHint,
staticHints, dynamicHints
) where
import Settings
import Hint.Type
import Hint.Match
import Hint.List
import Hint.ListRec
import Hint.Monad
import Hint.Lambda
import Hint.Bracket
import Hint.Naming
import Hint.Structure
import Hint.Import
import Hint.Pragma
import Hint.Extensions
import Hint.Duplicate
staticHints :: [(String,Hint)]
staticHints =
["List" ! listHint
,"ListRec" ! listRecHint
,"Monad" ! monadHint
,"Lambda" ! lambdaHint
,"Bracket" ! bracketHint
,"Naming" ! namingHint
,"Structure" ! structureHint
,"Import" + importHint
,"Pragma" + pragmaHint
,"Extensions" + extensionsHint
,"Duplicate" * duplicateHint
]
where
x!y = (x,DeclHint y)
x+y = (x,ModuHint y)
x*y = (x,CrossHint y)
dynamicHints :: [Setting] -> Hint
dynamicHints = DeclHint . readMatch
hlint-1.8.53/data/ 0000755 0000000 0000000 00000000000 12220306165 012022 5 ustar 00 0000000 0000000 hlint-1.8.53/data/Test.hs 0000644 0000000 0000000 00000004175 12220306165 013304 0 ustar 00 0000000 0000000 -- 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.Naming
error = Prelude.readFile ==> bad
error = (x :: Int) ==> (x :: Int32)
where _ = notTypeSafe
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
error = zip [1..length x] x ==> zipFrom 1 x
{-
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
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
zip [1..length x]
zip [1..length x] x -- zipFrom 1 x
-}
hlint-1.8.53/data/report_template.html 0000644 0000000 0000000 00000006567 12220306165 016134 0 ustar 00 0000000 0000000
HLint Report
Report generated by HLint
$VERSION
- a tool to suggest improvements to your Haskell code.
$CONTENT
hlint-1.8.53/data/hs-lint.el 0000644 0000000 0000000 00000007623 12220306165 013732 0 ustar 00 0000000 0000000 ;;; hs-lint.el --- minor mode for HLint code checking
;; Copyright 2009 (C) Alex Ott
;;
;; Author: Alex Ott
;; 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
hlint-1.8.53/data/HLint.hs 0000644 0000000 0000000 00000000127 12220306165 013374 0 ustar 00 0000000 0000000
module HLint.HLint where
import "hint" HLint.Default
import "hint" HLint.Builtin.All
hlint-1.8.53/data/hlint.ghci 0000644 0000000 0000000 00000002433 12220306165 013776 0 ustar 00 0000000 0000000 -- -*- mode: haskell; -*-
-- Begin copied material.
--
:{
: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 \""
:}
--- 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"
]
:}
hlint-1.8.53/data/hlint.1 0000644 0000000 0000000 00000002425 12220306165 013225 0 ustar 00 0000000 0000000 .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
for the Debian system (but may be used by others).
hlint-1.8.53/data/Generalise.hs 0000644 0000000 0000000 00000000272 12220306165 014435 0 ustar 00 0000000 0000000
module HLint.Generalise where
import Data.Monoid
import Control.Monad
warn = concatMap ==> (=<<)
warn = liftM ==> fmap
warn = map ==> fmap
warn = a ++ b ==> a `Data.Monoid.mappend` b
hlint-1.8.53/data/Dollar.hs 0000644 0000000 0000000 00000000220 12220306165 013565 0 ustar 00 0000000 0000000
module HLint.Dollar where
error = a $ b $ c ==> a . b $ c
{-
yes = concat $ concat $ map f x -- concat . concat $ map f x
-}
hlint-1.8.53/data/Default.hs 0000644 0000000 0000000 00000057405 12220306165 013755 0 ustar 00 0000000 0000000
module HLint.Default where
import Control.Arrow
import Control.Exception
import Control.Monad
import Control.Monad.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
error = x == a || x == b || x == c ==> x `elem` [a,b,c] where note = ValidInstance "Eq" x
error = 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
error = last (sortBy f x) ==> maximumBy f x
error "Avoid reverse" = reverse (sort x) ==> sortBy (flip compare) x
error "Avoid reverse" = reverse (sortBy f x) ==> sortBy (flip f) x
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
error = map f (replicate n x) ==> replicate n (f x)
error = map f (repeat x) ==> repeat (f x)
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 = 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
-- FOLDS
error = foldr (>>) (return ()) ==> sequence_
error = foldr (&&) True ==> and
error = foldl (&&) True ==> and where note = IncreasesLaziness
error = foldr1 (&&) ==> and where note = RemovesError "on []"
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
-- 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
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
-- 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 = not (isControl a) ==> isPrint a
error = isLower a || isUpper a ==> isAlpha a
error = isAlpha a || isDigit a ==> isAlphaNum 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
-- 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
error "Functor law" = fmap id ==> id
-- MONAD
error "Monad law, left identity" = return a >>= f ==> f a
error "Monad law, right identity" = m >>= return ==> m
warn = m >>= return . f ==> Control.Monad.liftM f m -- 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)
error = (if x then y else return ()) ==> Control.Monad.when x y where _ = isAtom y
error = (if x then return () else y) ==> Control.Monad.unless x $ _noParen_ y where _ = not (isAtom y)
error = (if x then return () else y) ==> Control.Monad.unless x y where _ = isAtom y
error = sequence (map f x) ==> mapM f x
error = sequence_ (map f x) ==> mapM_ f x
warn = flip mapM ==> Control.Monad.forM
warn = flip mapM_ ==> Control.Monad.forM_
warn = flip forM ==> mapM
warn = flip forM_ ==> mapM_
error = when (not x) ==> unless x
error = x >>= id ==> Control.Monad.join x
error = liftM f (liftM g x) ==> liftM (f . g) x
error = fmap f (fmap g x) ==> fmap (f . g) x
warn = a >> return () ==> void a
warn = fmap (const ()) ==> void
error = flip (>=>) ==> (<=<)
error = flip (<=<) ==> (>=>)
error = (\x -> f x >>= g) ==> f Control.Monad.>=> g
error = (\x -> f =<< g x) ==> f Control.Monad.<=< g
error = a >> forever a ==> forever a
warn = liftM2 id ==> ap
error = mapM (uncurry f) (zip l m) ==> zipWithM f l m
-- STATE MONAD
error = fst (runState x y) ==> evalState x y
error = snd (runState x y) ==> execState x y
-- MONAD LIST
error = liftM unzip (mapM f x) ==> Control.Monad.mapAndUnzipM f x
error = sequence (zipWith f x y) ==> Control.Monad.zipWithM f x y
error = sequence_ (zipWith f x y) ==> Control.Monad.zipWithM_ f x y
error = sequence (replicate n x) ==> Control.Monad.replicateM n x
error = sequence_ (replicate n x) ==> Control.Monad.replicateM_ n x
error = mapM f (replicate n x) ==> Control.Monad.replicateM n (f x)
error = mapM_ f (replicate n x) ==> Control.Monad.replicateM_ n (f x)
error = mapM f (map g x) ==> mapM (f . g) x
error = mapM_ f (map g x) ==> mapM_ (f . g) x
error = mapM id ==> sequence
error = mapM_ id ==> sequence_
-- APPLICATIVE / TRAVERSABLE
error = flip traverse ==> for
error = flip for ==> traverse
error = flip traverse_ ==> for_
error = flip for_ ==> traverse_
error = foldr (*>) (pure ()) ==> sequenceA_
error = foldr (<|>) empty ==> asum
error = liftA2 (flip ($)) ==> (<**>)
error = Just <$> a <|> pure Nothing ==> optional a
-- 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
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
-- INFIX
warn "Use infix" = X.elem x y ==> x `X.elem` y where _ = not (isInfixApp original) && not (isParen result)
warn "Use infix" = X.notElem x y ==> x `X.notElem` y where _ = not (isInfixApp original) && not (isParen result)
warn "Use infix" = X.isInfixOf x y ==> x `X.isInfixOf` y where _ = not (isInfixApp original) && not (isParen result)
warn "Use infix" = X.isSuffixOf x y ==> x `X.isSuffixOf` y where _ = not (isInfixApp original) && not (isParen result)
warn "Use infix" = X.isPrefixOf x y ==> x `X.isPrefixOf` y where _ = not (isInfixApp original) && not (isParen result)
warn "Use infix" = X.union x y ==> x `X.union` y where _ = not (isInfixApp original) && not (isParen result)
warn "Use infix" = X.intersect x y ==> x `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
warn = log y / log x ==> logBase x y
warn = sin x / cos x ==> tan x
warn = sinh x / cosh x ==> tanh 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 = a `seq` return a ==> Control.Exception.evaluate 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
error "Use Foldable.forM_" = when (isJust m) (f (fromJust m)) ==> Data.Foldable.forM_ m f
-- 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" = id x ==> x
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
{-
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 . id -- Control.Monad.liftM id 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 = Map.union a b -- a `Map.union` b
yes = [v | v <- xs] -- xs
no = [Left x | Left x <- xs]
yes = Map.union a b -- a `Map.union` b
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
main = print $ map (\_->5) [2,3,5] -- const 5
main = x == a || x == b || x == c -- x `elem` [a,b,c]
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 |])
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')
-}