我是一名学习Haskell的Java程序员。 我写了一个小程序,在文件中搜索带有特定后缀的单词。
我想读你的批评。 你有什么建议让这段代码更紧凑和可读?
module Main where
import Control.Monad
import Data.String.Utils
import Data.List
import Data.Char
import System.Directory
import System.FilePath
import System.IO
import System.IO.HVFS.Utils
import Text.Regex
alphaWords :: String -> [String]
alphaWords = words . map (\c -> if isAlpha c then c else ' ') -- by ephemient
-- was:
-- words2 s = case dropWhile isSpace2 s of
-- "" -> []
-- ss -> w : words2 sss
-- where (w, sss) = break isSpace2 ss
-- where isSpace2 = not . isAlpha
findFiles :: FilePath -> IO [FilePath]
findFiles path = do
cur_path <- getCurrentDirectory
files <- recurseDir SystemFS $ normalise $ combine cur_path path
filterM doesFileExist files
wordsWithSuffix :: String -> String -> [String]
wordsWithSuffix suffix text =
let tokens = (nub . alphaWords) text
endswithIgnoringCase = endswith suffix . map toLower
in filter endswithIgnoringCase tokens
searchWords :: String -> String -> [String] -> IO [String]
searchWords suffix path exts = do
let isSearchable = (`elem` exts) . takeExtension -- by yairchu
--was let isSearchable s = takeExtension s `elem` exts
--files <- filterM (fmap isSearchable) $ findFiles path -- by ephemient (compile error)
files <- liftM (filter isSearchable) $ findFiles path
wordsPerFile <- forM files $ fmap (wordsWithSuffix suffix) . readFile -- by ephemient
-- was: wordsPerFile <- forM files (\x -> liftM (wordsWithSuffix suffix) (readFile x))
return . sort . nub $ concat wordsPerFile -- by ephemient
-- was: return $ (sort . nub . concat) wordsPerFile
main = do
words <- searchWords "tick" "/path/to/src" [".as", ".java", ".mxml"]
print $ length words
putStrLn $ unlines words
更新:我修复了使用“hlint”找到的2个详细点,谢谢@yairchu
更新2 :更多修复。谢谢@ephemient
更新3:一个小修复。谢谢@yairchu,不能使用你的所有代码 - 对于Java开发人员来说太难了
答案 0 :(得分:4)
如果您不需要,请不要import System.FilePath.Posix
。 System.FilePath
根据您正在编译的平台导出System.FilePath.Posix
或System.FilePath.Windows
。
您的words2
实施没有问题,但对于为什么它执行的操作缺乏任何解释。这更加不言自明,效率差异也不大。
alphaWords = words . map (\c -> if isAlpha c then c else ' ')
searchWords
:
- wordsPerFile <- forM files (\x ->
- liftM (wordsWithSuffix suffix) (readFile x))
+ wordsPerFile <- forM files $ fmap (wordsWithSuffix suffix) . readFile
- return $ (sort . nub . concat) wordsPerFile
+ return . sort . nub $ concat wordsPerFile
在let
构造中输入注释并不常见,除非类型检查器确实需要帮助...但如果我注意它们,我就不会犯下我之前尝试移动的错误isSearchable
:)
另外,在main
中,我会改变这一点:
- putStrLn $ unlines words
+ mapM_ putStrLn words
我不熟悉MissingH公开的模块;是System.IO.HVFS.Utils.recurseDir
懒惰?如果没有,添加System.IO.Unsafe.unsafeInterleaveIO
可能有助于在遍历大型目录树时消耗内存。
答案 1 :(得分:2)
首先,首先询问hlint。
它会为您提供一些有用的建议和课程,例如:
homework.hs:46:1: Error: Use print
Found:
putStrLn $ show $ length words
Why not:
print (length words)
所以我们看到print = putStrLn . show
等
答案 2 :(得分:2)
我不喜欢变量名。
因此,这是一个较短的searchWords
:
searchWords :: String -> String -> [String] -> IO [String]
searchWords suffix path exts =
fmap (sort . nub . concatMap (wordsWithSuffix suffix)) .
mapM readFile . filter ((`elem` exts) . takeExtension)
=<< findFiles path