我的代码应该采用字符串,例如ccccchhrrre
并返回成对列表[('c', 5) , ('h', 2) , ('r', 3), ('e', 1)]
。该对的第一部分是字母,第二部分是重复直到下一个字符串出现的次数。
但是,当前,我的代码返回[('c',11)]
-这是字符串中的第一个字符和字符总数的长度:
> fun4 "ccccchhrrre"
[('c',11)]
我的问题是fun4
。运行 func3
> fun3 "ccccchhrrre"
["ccccc","hh","rrr","e"]
fun3 :: String -> [String]
fun3 "" = []
fun3 xs = fun2 xs : fun3 (drop(length(fun2 xs))xs)
func4 :: String -> [(Char, Int)]
func4 fun3 = zip (fun3)[length fun3]
我感谢提供详细说明的任何帮助。
答案 0 :(得分:4)
有两个问题。首先是,当您编写以下内容时:
func4 :: String -> [(Char, Int)]
func4 fun3 = zip (fun3)[length fun3]
此定义中的fun3
与您先前定义的fun3
函数完全没有关联。如果您打开了编译器警告(例如,使用标志-Wall
),则会警告您在此fun3
定义中,func4
的绑定会“阴影”现有的绑定。这意味着它的使用方式与您使用完整的单独名称相同:
func4 :: String -> [(Char, Int)]
func4 bob = zip (bob) [length bob]
因此,当您评估时:
func4 "ccccchhrrre"
根本不使用函数fun3
。相反,它通过func4
的定义扩展为:
func4 "ccccchhrrre"
= zip "ccccchhrrre" [length "ccccchhrrre"]
= zip "ccccchhrrre" [11]
并且由于Haskell中的字符串是字符列表,因此与以下内容相同:
= zip ['c','c',...] [11]
当您压缩两个列表并且一个列表比另一个列表短时,当列表用完时,zip结束,因此产生:
= [('c', 11)]
,并忽略字符列表的第二个和后续元素。
您可能想要的是编写func4
以获取字符串参数并将其传递给fun3
:
func4 :: String -> [(Char, Int)]
func4 xs = zip (fun3 xs) [length (fun3 xs)]
不幸的是,这不会输入check。问题是,这等效于:
func4 "ccccchhrrre"
= zip ["ccccc","hh","rrr","e"] [length ["ccccc","hh","rrr","e"]]
= zip ["ccccc","hh","rrr","e"] [4]
= [("ccccc", 4)]
其类型为[(String, Char)]
,而不是您期望的[(Char, Char)]
。
如果您了解了map
,可能会认为了解以下信息很有用:
> map head ["ccccc","hh","rrr","e"]
"chre"
>
和"chre"
等同于列表['c','h','r','e']
。如果您能以某种方式获得长度列表[5,2,3,1]
的方式与获得头部列表的方式相同,那么这些列表将非常有用。
如果您不想使用map
,可能会发现编写func4
来处理fun3
的 output 很有帮助,就像这样:
> func4 ["ccccc","hh","rrr","e"]
[('c',5),('h',2),('r',3),('e',1)]
>
签名会稍有不同,但结构与您的fun3
类似:
func4 :: [String] -> [(Char, Int)]
func4 [] = []
func4 (str : strs) = ??? : func4 strs
,然后您的最终函数可以将fun3
和func4
链接在一起:
rle :: String -> [(Char, Int)]
rle str = func4 (fun3 str)
答案 1 :(得分:0)
other answer为您的代码中的问题提供了很好的解释。这是一个略有不同的解决方案,我发现它更容易理解。
fun3
可以替换为现有功能Data.List.group
。 group
获取一个列表并生成一个列表列表,其中包含相等的相邻元素:
> Data.List.group "ccccchhrrre"
["ccccc","hh","rrr","e"]
使用fun4
也可以简化map
应该执行的工作。匿名函数\x -> (head x, length x)
接受一个参数x
,并生成一个元组,其第一个元素为x的头,第二个元素为x的长度。将此函数映射到group
的输出上应该可以为我们提供所需的结果:
> map (\x -> (head x, length x)) ["ccccc","hh","rrr","e"]
[('c',5),('h',2),('r',3),('e',1)]
我们现在可以将group
和我们的map
合并为一个函数,并为其指定一个更合适的名称:
-- Count adjacent repeated characters
countRep :: String -> [(Char, Int)]
countRep str = map (\x -> (head x, length x)) (List.group str)
我们编写的函数可在可以比较其项是否相等的任何列表上使用!这里是无点样式:
countRep :: Eq a => [a] -> [(a, Int)]
countRep = map (liftA2 (,) head length) . List.group