我正在尝试编写一个函数[a] -> Bool
,当列表的所有元素具有相同的长度时,它返回true。
我尝试使用列表递归执行此操作,并使用x : y : xs
提取列表的前两个元素,然后将x和y的长度与length x == length y
进行比较,作为大小写确定。但是,GHCi
抱怨x和y的类型:
Couldn't match expected type `a' with actual type `[a0]'
`a' is a rigid type variable bound by
the type signature for [a] -> Bool
In the first argument of `length', namely `x'
In the first argument of `(==)', namely `length x'
In the expression: length x == length y
为什么会发生这种情况,我该如何解决?显然,length :: [a] -> Int == length :: [a] -> Int
会返回正确的Bool
。实际上,用True
替换此表达式会编译。
答案 0 :(得分:4)
实际上,我们可以非常简单地做到这一点。
sameLengths :: [[a]] -> Bool
sameLengths [] = True
sameLengths (x:xs) = all (\y -> length y == length x) xs
不需要任何递归 - 如果它们等于第一个长度,则所有长度都相同,所以只需提取第一个并使用all
轻松检查其余部分。
至于您为[a]
定义的原因,请记住[String]
是[[a]]
以及[a]
。但我们特别需要[[a]]
,因为必须为length
中的a
定义[a]
。
答案 1 :(得分:0)
有两个问题:
length
函数是在列表(length :: [a] -> Int
)上定义的,所以你
不能将其应用于其他类型
你当然可以定义一个自己的类:
class WithLength a where
myLength :: a -> Bool
但您必须为每种可能的类型定义此类的实例!例如:
instance WithLength Int where
myLength _ = 1
instance WithLength [a] where
myLength lst = length lst
然后,您可以定义递归函数以检查相同长度的属性。
答案 2 :(得分:0)
到目前为止给出的答案在列表中至少有一个列表是有限的并且至少有一个是无限的时候不能正常工作:当终止可能时,函数无法终止,因为它们正忙着调用{{1在无限列表上。以下是适用于任何类型列表的答案:
length
这是一个非常简单的递归定义:要么所有列表都是空的,要么都不是空的,并且从每个列表中取出一个元素后它们的长度仍然相同。