Haskell文件行数统计:移除for循环及函数重构咨询
Haskell脚本重构方案
1. 移除for_循环的替代方案
你当前依赖的System.Directory.Internal.Prelude.for_属于内部模块,不建议直接使用。可以用标准库Control.Monad中的mapM_或forM_替代,它们是专门用于遍历并执行IO动作的标准函数:
方案一:使用mapM_
mapM_接收IO动作和列表,会依次对列表元素执行动作并忽略返回结果,完全匹配你的需求。修改后的main函数如下:
import System.Environment import System.Directory import System.IO import Control.Monad (mapM_) main = do (configPath:_) <- getArgs configContents <- readFile configPath let filePaths = lines configContents mapM_ getFileLength filePaths getFileLength :: FilePath -> IO() getFileLength path = do contents <- readFile path putStrLn $ "- [ ] " ++ path ++ " (" ++ show (length (lines contents)) ++ ")"
方案二:使用标准库的forM_
如果你习惯“列表在前、函数在后”的写法,可以导入Control.Monad.forM_,它和原内部for_行为一致,但属于公开标准接口:
import System.Environment import System.Directory import System.IO import Control.Monad (forM_) main = do (configPath:_) <- getArgs configContents <- readFile configPath let filePaths = lines configContents forM_ filePaths getFileLength getFileLength :: FilePath -> IO() getFileLength path = do contents <- readFile path putStrLn $ "- [ ] " ++ path ++ " (" ++ show (length (lines contents)) ++ ")"
2. 重构为FilePath -> IO (Maybe Int)的方案(问题合理)
这个修改非常合理:原版本直接用readFile,若文件不存在、无权限或出现IO错误,程序会直接崩溃。改成返回Maybe Int能优雅处理错误,大幅提升程序健壮性。
重构后完整代码
import System.Environment import System.IO import Control.Monad (mapM_) import Control.Exception (try, IOException) main = do (configPath:_) <- getArgs configContents <- readFile configPath let filePaths = lines configContents mapM_ processFile filePaths -- 新的getFileLength:捕获IO异常,返回Maybe Int getFileLength :: FilePath -> IO (Maybe Int) getFileLength path = do result <- try (readFile path) :: IO (Either IOException String) case result of Right contents -> return $ Just $ length (lines contents) Left _ -> return Nothing -- 新增处理函数,根据结果打印对应信息 processFile :: FilePath -> IO () processFile path = do maybeLines <- getFileLength path case maybeLines of Just n -> putStrLn $ "- [ ] " ++ path ++ " (" ++ show n ++ ")" Nothing -> putStrLn $ "- [x] " ++ path ++ " (读取失败)"
关键说明
- 用
Control.Exception.try捕获readFile可能抛出的IOException,将结果转为Either IOException String; - 通过
case表达式处理成功/失败场景,返回对应的Maybe Int; - 新增
processFile分离“获取行数”和“打印结果”的职责,代码逻辑更清晰。
内容的提问来源于stack exchange,提问作者red-swan
相关产品推荐
相关产品推荐

