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

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操作是“纯函数式”的,所以所有涉及文件读写、打印的代码都要放在IO monad里,刚开始可能有点懵,多写几次就习惯了。
  • 处理列表时多用模式匹配(比如splitTestCases里的(totalGroups:restNumbers)),这是Haskell的核心技巧,能帮你少写很多条件判断。
  • 遇到类型错误别慌——Haskell的类型系统是帮你找bug的,仔细看错误提示,慢慢就能理解它的逻辑了。

内容的提问来源于stack exchange,提问作者singher

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 08:56:56