Haskell中StrLst类型下字符串列表总字符数计算函数实现求助
问题背景
我需要写两个函数charLena和charLenb,用来计算自定义类型StrLst里对应字符串列表的总字符数。举个实际的例子:
charLena (createStrLst ["avd", "d4sf"] ["asvd","a2e","bdsh"]) -- 应该输出7,也就是第一个列表里所有字符串的字符总数 charLenb (createStrLst ["avd", "d4sf"] ["asvd","a2e","bdsh"]) -- 应该输出11,对应第二个列表的总字符数
目前已经有这些可用的代码和辅助函数:
data StrLst = StrLst [String] [String] deriving (Eq) createStrLst :: [String] -> [String] -> StrLst numa :: StrLst -> Int -- 返回第一个列表的字符串数量 numb :: StrLst -> Int -- 返回第二个列表的字符串数量 lena :: StrLst -> Int -> Int -- 第一个列表中第i+1个字符串的长度(注意i是从0开始的索引) lenb :: StrLst -> Int -> Int -- 第二个列表中第i+1个字符串的长度 createStrLst a b = (StrLst a b) numa (StrLst a b) = length a numb (StrLst a b) = length b lena (StrLst a b) i = length (a!!i) lenb (StrLst a b) i = length (b!!i)
我知道可以用map、递归或者Haskell基础命令,但不知道怎么对StrLst这种自定义类型用map,希望有人能指导一下。
解决方案
其实有几种不同的实现思路,我给你一一说明,你可以根据自己的需求选择:
1. 最简洁的方式:直接模式匹配+sum+map
既然StrLst的构造函数本身就包含两个字符串列表,我们可以直接通过模式匹配取出对应的列表,然后用常规的列表操作计算总长度:
charLena :: StrLst -> Int charLena (StrLst firstStrs _) = sum (map length firstStrs) charLenb :: StrLst -> Int charLenb (StrLst _ secondStrs) = sum (map length secondStrs)
这个思路最直接——我们跳过辅助函数,直接访问StrLst内部的字符串列表,用map length把每个字符串转成它的长度,再用sum把所有长度加起来就行。
2. 用给定的辅助函数+递归
如果要求必须用你提供的numa、lena这些辅助函数,那我们可以用递归来遍历每个索引,累加长度:
charLena :: StrLst -> Int charLena strList = calculateFromIndex 0 where calculateFromIndex i | i >= numa strList = 0 -- 索引越界,停止递归 | otherwise = lena strList i + calculateFromIndex (i + 1) -- 累加当前长度,继续下一个索引 charLenb :: StrLst -> Int charLenb strList = calculateFromIndex 0 where calculateFromIndex i | i >= numb strList = 0 | otherwise = lenb strList i + calculateFromIndex (i + 1)
这里的calculateFromIndex是内部递归函数,从索引0开始,每次把当前字符串的长度加到结果里,直到索引超过列表的元素数量为止。
3. 用给定的辅助函数+map+sum
如果想用map的话,我们可以先生成所有有效的索引,再用map把每个索引转换成对应的字符串长度,最后求和:
charLena :: StrLst -> Int charLena strList = sum $ map (lena strList) [0 .. numa strList - 1] charLenb :: StrLst -> Int charLenb strList = sum $ map (lenb strList) [0 .. numb strList - 1]
解释一下:[0 .. numa strList -1]生成了从0到第一个列表最后一个元素索引的列表,map (lena strList)把每个索引变成对应的字符串长度,最后sum把这些长度加起来得到总数。
小提示
你之前觉得没法对StrLst用map,是因为map是专门作用于列表的高阶函数,而StrLst是自定义的数据类型,不是列表。但我们可以先通过模式匹配或者辅助函数,把StrLst内部的列表(或者有效索引范围)取出来,再对这些内容用map就完全没问题啦。
内容的提问来源于stack exchange,提问作者karmo20

