You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 18:30:54