如何使这段代码更紧凑和可读?

时间:2009-07-07 14:47:59

标签: haskell coding-style

我是一名学习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开发人员来说太难了

3 个答案:

答案 0 :(得分:4)

如果您不需要,请不要import System.FilePath.PosixSystem.FilePath根据您正在编译的平台导出System.FilePath.PosixSystem.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