2009-07-07 9 views
3

私はハスケルを学ぶ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 

UPDATE:その他の修正:私は "hlint" を使用した2つの冗長スポット、
UPDATE 2 @yairchu感謝を修正しました。ありがとう@ephemient
更新3:少し修正。ありがとう@yairchu、あなたのコードのすべてを使用することはできません - Java開発者の心のためにあまりにも難しい

+1

本当の質問ではありませんか? – maxwellb

+2

この宿題はありますか? –

+1

実装を作成し、他の人にあなたのためにそれをさせるのではなく、最適化の助けを頼むようにしてください。さもなければ、私はあなたのためにこれを開発するためにHaskellのプログラマーを雇うことを提案したいと思います。 – Lazarus

答えて

4

はないimport System.FilePath.Posixを行います。 System.FilePathは、コンパイルしているプラ​​ットフォームに従ってSystem.FilePath.PosixまたはSystem.FilePath.Windowsをエクスポートします。

お客様のwords2実装は問題ありませんが、についての理由はありません。は何をしていますか。これは自明であり、効率の差は重要ではありません。 searchWords

alphaWords = words . map (\c -> if isAlpha c then c else ' ') 

リトル改善:

- 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構造内部の型注釈が一般的ではありません...私は彼らに注意を払っていた場合、私は作っていないだろうけれどもmainで、またisSearchable :)

移動しようとしているの私の以前のミス、私はこれを変更します

- putStrLn $ unlines words 
+ mapM_ putStrLn words 

私はMissingHによって公開されたモジュールに精通していません。 System.IO.HVFS.Utils.recurseDirは遅延ですか?そうでない場合は、System.IO.Unsafe.unsafeInterleaveIOを追加すると、大きなディレクトリツリーを走査するときのメモリ消費に役立ちます。

+0

問題: "ファイル< - filterM isSearchable $ findFilesパス" タイプが "filterM ::(Monad m)=>(a - > m Bool) - > [a] - > m [a]" "filterM ::(Monad m)=>(a - > Bool) - > m [a] - > m [a]" – oshyshko

+0

ああ、コンパイルテストはしませんでした。 'filterM(fmap isSearchable)'が必要になります。 – ephemient

+0

「ファイル< - filterM(fmap isSearchable)」に編集されました。$ findFiles path " - got"予想される型 '[m FilePath] 'を推定型' IO [FilePath]'と照合できませんでした " – oshyshko

2

まず、質問から始めます。

それは次のように、あなたにいくつかの有益な提案や教訓を与えるだろう:私たちは、私は変数名を好きではないprint = putStrLn . show

など

+0

hlint岩。ありがとう。どのように "searchWords"機能を簡略化しますか? – oshyshko

2

ていることがわかり

homework.hs:46:1: Error: Use print 
Found: 
    putStrLn $ show $ length words 
Why not: 
    print (length words) 

。したがって、ここで

は短い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 
+1

短いです。読者に依存しています:-Dとにかく私にはうまく見えます。 (Excression: 'Prelude.fmap'が行うときに' Control.Monad.liftM'を使うのはなぜですか?) – ephemient

+0

@ephemient:それは厄介な習慣です。 Monadsの汎用コードを書くことからMonadは自動的にFunctorを意味するわけではありません。 – yairchu

+1

ハスケルでは厄介な癖よりも厄介な疣贅です。 Monadは、ApplicativeとFunctorの両方を暗示する必要があります。 – Alasdair

関連する問題