我正试图从九十九个haskell问题中解决problem 10。 这是我认为正确的解决方案。
包装功能(问题9)已经正确。问题在于编码功能。
pack :: (Eq a) => [a] -> [[a]]
pack [] = []
pack (x:xs) = (x : takeWhile (== x) xs) : (pack $ dropWhile (== x) xs)
encode :: (Eq a) => [a] -> [(Int, a)]
encode [] = []
encode list = (encode' $ head packed) : (encode $ tail packed)
where packed = pack list
encode' l = (length l, head l)
当我从ghci加载文件时,这是错误:
encode.hs:6:0: 发生检查:无法构造无限类型:a = [a] 在推广`encode'的类型时
第6行是包含encode [] = []
我的编码功能出了什么问题?我一直在检查所用变量的类型,我相信没有错。
函数用法示例(假设代码工作正常):
pack "aaaabbbbccccccddddddd"
> ["aaaa","bbbb","cccccc","ddddddd"]
encode "aaaabbbbccccccddddddd"
> [(4,'a'),(4,'b'),(6,'c'),(7,'d')]
答案 0 :(得分:4)
递归在这里有些笨拙。使用更高阶函数要好得多。
您已经有一个函数encode' :: [a] -> (Int, a)
来编码一个子列表,并且您希望对所有子列表进行编码。将函数应用于列表的每个元素是一种非常常见的模式,它由高阶函数map :: (a -> b) -> [a] -> [b]
封装。
利用map
,我们可以简单地写一下:
encode :: (Eq a) => [a] -> [(Int, a)]
encode list = map encode' $ pack list
where encode' xs = (length xs, head xs)
您还可以使用列表解析来避免辅助函数:
encode :: (Eq a) => [a] -> [(Int, a)]
encode list = [(length xs, head xs) | xs <- pack list]
通常,尝试在适当的地方使用现有的高阶函数,而不是自己进行递归。它更具可读性,更不容易出错。
答案 1 :(得分:3)
encode $ tail packed
我们有
packed :: [[a]]
tail packed :: [[a]]
但我们需要将[a]
传递给encode
。
(想想这样:list
需要通过pack
。packed
是pack
的输出,但在递归调用中它会被传递给再次pack
。)
答案 2 :(得分:2)
您的问题是函数encode
需要“解压缩”列表,但您传递的是“打包”列表。
添加类型签名对此有很大帮助,我为encode'
{-# LANGUAGE ScopedTypeVariables #-}
pack :: (Eq a) => [a] -> [[a]]
pack [] = []
pack (x:xs) = (x : takeWhile (== x) xs) : (pack $ dropWhile (== x) xs)
encode :: forall a. (Eq a) => [a] -> [(Int, a)]
encode [] = []
encode list = (encode' $ head packed) : (encode $ tail packed)
where packed = pack list
encode' :: [a] -> (Int, a)
encode' l = (length l, head l)
,编译器快速找到错误:
[1 of 1] Compiling Main ( test.hs, interpreted )
test.hs:9:42:
Couldn't match type `a' with `[a]'
`a' is a rigid type variable bound by
the type signature for encode :: Eq a => [a] -> [(Int, a)]
at test.hs:8:1
Expected type: [(Int, a)]
Actual type: [(Int, [a])]
In the second argument of `(:)', namely `(encode $ tail packed)'
In the expression: (encode' $ head packed) : (encode $ tail packed)
Failed, modules loaded: none.
因为仅当a
与[a]
相同且因此与[[a]]
等相同时才会有效。这是无限类型错误。或者只是样本中“打包”列表([[a]]
)和“解压缩”列表([a]
)之间的差异。
(为了更好地理解:“打包”列表是应用pack
函数后的列表;-))
编辑:修复了ScopedTypeVariables与ExistentialQuantification错误,感谢John L
答案 3 :(得分:1)
您可以对要打包的结果进行模式匹配,而不是使用head
和tail
。
然后它看起来像这样:
encode :: (Eq a) => [a] -> [(Int, a)]
encode [] = []
encode list = encode' x : encode xs
where (x:xs) = pack list
encode' l = (length l, head l)
来自xs
的类型错误属于[[a]]
类型,因为pack
返回[[a]]
,但encode
需要[a]
参数。
答案 4 :(得分:1)
我同意@hammar的观点,即高阶函数是处理这个问题的好方法 以下是对所发生情况的一般性解释:
每当我遇到无限类型错误时,它都有以下形式:
我有一个自我调用的函数,但用比我们传递的“更深”*类型调用自己。
让我们做一个简单的无限类型错误:
*Main> let f (_:xs) = f [xs]
<interactive>:1:19:
Occurs check: cannot construct the infinite type: t0 = [t0]
让我们分解原因:无法确定f
的类型:如果f :: [a] -> [[a]]
,那么f [xs] :: [[a]] -> [[[a]]]
会传递给原f
,它无法返回[[[a]]]
。
*我对“更深层”的定义:
[[a]]
比[a]
更“深”
Constructor (Constructor a)
比Constructor a