List 使用列表和zip的Haskell函数的输出不正确

List 使用列表和zip的Haskell函数的输出不正确,list,haskell,List,Haskell,我的代码应该是一个字符串,例如,cccccchhrre并返回对的列表[('c',5),('h',2),('r',3),('e',1)]。该对的第一部分是字母,第二部分是在出现下一个字符串之前重复的次数 但是,当前我的代码返回[('c',11)]-这是字符串中的第一个字符和总字符数的长度: > fun4 "ccccchhrrre" [('c',11)] 我的问题是fun4。运行func3时 我非常感谢您的帮助,包括详细的解释。这里有几个问题。第一个是,当你写作时: func4 :: Str

我的代码应该是一个字符串,例如,
cccccchhrre
并返回对的列表
[('c',5),('h',2),('r',3),('e',1)]
。该对的第一部分是字母,第二部分是在出现下一个字符串之前重复的次数

但是,当前我的代码返回
[('c',11)]
-这是字符串中的第一个字符和总字符数的长度:

> fun4 "ccccchhrrre"
[('c',11)]
我的问题是
fun4
。运行func3时


我非常感谢您的帮助,包括详细的解释。

这里有几个问题。第一个是,当你写作时:

func4 :: String -> [(Char, Int)]
func4 fun3 = zip (fun3)[length fun3]
此定义中的
fun3
与您先前定义的
fun3
函数没有任何关系。如果您打开编译器警告(例如,使用标志
-Wall
),它将警告您在
func4
的此定义中
fun3
的绑定“隐藏”了现有绑定。这意味着它的处理方式与使用完整的单独名称相同:

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]
当您压缩两个列表,其中一个比另一个短时,压缩会在列表用完时结束,因此会产生:

= [('c', 11)]
并忽略字符列表的第二个和后面的元素

您可能想要的是编写
func4
以获取字符串参数并将其传递给
fun3

func4 :: String -> [(Char, Int)]
func4 xs = zip (fun3 xs) [length (fun3 xs)]
func4 :: [String] -> [(Char, Int)]
func4 [] = []
func4 (str : strs) = ??? : func4 strs
不幸的是,这不会进行类型检查。问题在于,这相当于:

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']
。如果你能以某种方式得到一个长度的列表,就像你得到一个头部列表一样,这些列表将非常有用

如果您不想使用
map
,您可能会发现编写一个
func4
来处理
fun3
的输出很有帮助,如下所示:

> func4 ["ccccc","hh","rrr","e"]
[('c',5),('h',2),('r',3),('e',1)]
>
它的签名稍有不同,但结构与您的
fun3

func4 :: String -> [(Char, Int)]
func4 xs = zip (fun3 xs) [length (fun3 xs)]
func4 :: [String] -> [(Char, Int)]
func4 [] = []
func4 (str : strs) = ??? : func4 strs
然后,您的最终函数可以将
fun3
fun4
链接在一起:

rle :: String -> [(Char, Int)]
rle str = func4 (fun3 str)
对代码中的问题提供了很好的解释。这里有一个稍微不同的解决方案,我觉得更容易理解

fun3
可以用现有函数替换<代码>组获取一个列表并生成一个列表列表,其中包含相等的相邻元素:

> Data.List.group "ccccchhrrre"
["ccccc","hh","rrr","e"]
fun4
应该执行的工作也可以通过使用
map
来简化。匿名函数
\x->(头x,长度x)
接受一个参数
x
,并生成一个元组,其第一个元素是x的头,第二个元素是x的长度。将此函数映射到
的输出上,可以得到所需的结果:

> map (\x -> (head x, length x)) ["ccccc","hh","rrr","e"]
[('c',5),('h',2),('r',3),('e',1)]
现在,我们可以将
和我们的
映射
组合成一个函数,并给它一个更合适的名称:

-- 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

什么是
fun2