Haskell实践:从文件读取数据并完成多组测试计算需求
Haskell新手实战:处理文件中的测试组计算
Hey there! 作为刚啃Haskell没多久的新手,我太懂你觉得它“难到离谱”的感受了——这货的函数式思路和咱们平时写的命令式代码完全不是一个路子,但拆成小问题一步步来的话,其实也能慢慢摸到门道~针对你说的这个真题练习,咱们一步步来实现:
第一步:读取并解析文件里的整数
首先得把myFile.txt里的那串数字读出来,转成整数列表。Haskell里用readFile读取文件内容,再用words按空格拆分,最后转成整数就行:
import Data.List (words) -- 从指定文件读取整数列表 readNumbers :: FilePath -> IO [Int] readNumbers filePath = do content <- readFile filePath return $ map read (words content)
第二步:拆分出测试组
文件里第一个数是测试组数,剩下的数字每两个一组就是测试用例。咱们写个辅助函数来拆分:
-- 把整数列表拆分成测试用例列表 splitTestCases :: [Int] -> [(Int, Int)] splitTestCases (totalGroups:restNumbers) = take totalGroups $ pairUp restNumbers where -- 把列表两两配对 pairUp [] = [] pairUp (a:b:xs) = (a, b) : pairUp xs pairUp _ = [] -- 处理剩余单个数字的边界情况(题目里应该不会出现) splitTestCases [] = [] -- 空文件的边界处理
这个函数先取第一个数作为总组数,然后把剩下的数字两两配对,取前totalGroups组就是咱们要处理的测试用例。
第三步:实现每组的计算逻辑
你提到每组(比如3 30)要返回一个乘积相关的结果(比如20)。虽然你没说具体规则,我先拿一个常见的乘积类真题逻辑举例子——比如计算第二个数的阶乘中包含第一个数的因子个数(也就是最大的x使得k^x能整除m!),你可以直接把这个函数换成你实际需要的逻辑:
-- 计算一个数的质因数分解(比如12会拆成[(2,2), (3,1)]) primeFactors :: Int -> [(Int, Int)] primeFactors n = factor n primes where factor 1 _ = [] factor n (p:ps) | p*p > n = [(n, 1)] | n `mod` p == 0 = let (count, remainder) = countDivisions n p in (p, count) : factor remainder ps | otherwise = factor n ps -- 统计n能被p整除多少次 countDivisions n p = let (c, r) = n `divMod` p in if r == 0 then countDivisions c p else (c, n) -- 生成质数列表(埃氏筛法) primes = sieve [2..] sieve (p:xs) = p : sieve [x | x <- xs, x `mod` p /= 0] -- 计算m!中包含k的因子个数 calculateResult :: Int -> Int -> Int calculateResult k m = minimum [ countPrimeInFactorial p exp | (p, exp) <- primeFactors k ] where -- 计算m!中包含质数p的个数 countPrimeInFactorial p exp = sum [ m `div` (p^i) | i <- [1..], p^i <= m ] `div` exp
如果你的真题规则是别的(比如计算两个数的乘积的某个衍生值),直接替换calculateResult函数就行,比如简单的calculateResult a b = a * b也可以。
第四步:整合所有步骤并输出结果
最后把这些部分拼起来,读取文件、拆分测试用例、计算结果,然后打印出来:
main :: IO () main = do allNumbers <- readNumbers "myFile.txt" let testCases = splitTestCases allNumbers results = map (\(a, b) -> calculateResult a b) testCases mapM_ print results
给新手的小提醒
- Haskell的IO操作是“纯函数式”的,所以所有涉及文件读写、打印的代码都要放在
IOmonad里,刚开始可能有点懵,多写几次就习惯了。 - 处理列表时多用模式匹配(比如
splitTestCases里的(totalGroups:restNumbers)),这是Haskell的核心技巧,能帮你少写很多条件判断。 - 遇到类型错误别慌——Haskell的类型系统是帮你找bug的,仔细看错误提示,慢慢就能理解它的逻辑了。
内容的提问来源于stack exchange,提问作者singher
相关产品推荐
相关产品推荐

