Haskell技术问题:如何将[(Char, Int)]元组列表写入文本文件?
Haskell 元音计数写入文件问题修复
问题场景
读取input.txt文本内容,统计其中元音字母(大小写aeyioAEYIO)的出现次数,得到[(Char, Int)]类型的元组列表,期望每行显示一个字母与对应计数并写入output.txt,但代码运行报错。
原代码
import Data.List import Char add :: Eq a => a -> [(a, Int)] -> [(a, Int)] add x [] = [(x, 1)] add x ((y, n):rest) = if x == y then (y, n+1) : rest else (y, n) : add x rest count :: Eq a => [a] -> [(a, Int)] count = sortBy f . foldr add [] where f (_, x) (_, y) = compare y x ff x = filter (\x->elem (fst x) "aeyioAEYIO") x fff x = ff (count x) main :: IO () main = do src <- readFile "input.txt" writeFile "output.txt" (operate src) operate :: [(Char, Int)] -> String operate = fff
报错信息
*** Term : operate *** Type : [Char] -> [(Char,Int)] *** Does not match : [(Char,Int)] -> String
错误原因
核心问题是类型不匹配:
fff函数的实际类型是[Char] -> [(Char, Int)](接收字符串,返回计数元组列表)- 你给
operate标注的类型是[(Char, Int)] -> String(接收元组列表,返回字符串),但代码里把operate直接绑定成了fff,导致类型完全反转。 - 另外,
writeFile要求传入String类型参数,但原代码直接传递元组列表,就算类型问题解决,也无法直接将元组转换为可写入的文本格式。
修复步骤
- 修正
operate的类型定义,让它接收字符串并返回格式化后的可写入字符串。 - 添加元组转字符串的逻辑,把每个
(Char, Int)元组转换成"字母: 次数\n"的格式,再拼接成完整文本。 - 替换过时的
Char模块导入为Data.Char,适配现代GHC版本。
修正后代码
import Data.List import Data.Char add :: Eq a => a -> [(a, Int)] -> [(a, Int)] add x [] = [(x, 1)] add x ((y, n):rest) = if x == y then (y, n+1) : rest else (y, n) : add x rest count :: Eq a => [a] -> [(a, Int)] count = sortBy f . foldr add [] where f (_, x) (_, y) = compare y x filterVowels :: [(Char, Int)] -> [(Char, Int)] filterVowels = filter (\(c, _) -> elem c "aeyioAEYIO") countVowels :: String -> [(Char, Int)] countVowels = filterVowels . count -- 将元组列表格式化为每行一个条目 formatResults :: [(Char, Int)] -> String formatResults = unlines . map (\(c, n) -> c : ": " ++ show n) operate :: String -> String operate = formatResults . countVowels main :: IO () main = do src <- readFile "input.txt" writeFile "output.txt" (operate src)
关键修正说明
- 重命名了原有的
ff、fff函数为更具语义的filterVowels、countVowels,提升代码可读性。 formatResults函数用map转换每个元组为字符串,再通过unlines自动添加换行符,满足每行一个条目的需求。- 修正后的
operate会先完成元音统计,再将结果格式化为可直接写入文件的字符串。 - 替换
import Char为import Data.Char,避免旧模块带来的编译警告。
内容的提问来源于stack exchange,提问作者Clark Brown
相关产品推荐
相关产品推荐

