所有相同长度函数
我想写一个函数[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
代替这个表达式编译。
实际上我们可以很简单地做到这一点。
sameLengths :: [[a]] -> Bool
sameLengths [] = True
sameLengths (x:xs) = all (\y -> length y == length x) xs
无需任何递归 - 所有的长度是相同的当且仅当它们等于第一个,所以只提取第一和使用all
轻松地检查休息。
至于为什么你不能定义为[a]
,请记住[String]
是[[a]]
以及[a]
。但我们特别需要[[a]]
,因为无论a
是[a]
,length
都必须定义。
@ThreeFx oops固定,谢谢。最初我只想写'(==长度x)。长度“(我更喜欢),但认为最好是为清晰度编写明确的lambda – alternative 2014-10-30 16:03:14
这对于像[[[],[1 ..]]这样的输入不起作用。 – amalloy 2014-10-30 18:47:55
@amalloy我想我们只考虑有限长度,因为无限列表...是无限的,没有长度,所以你永远不会知道例如[[1 ..],[1 ..]]是否应该返回true或错误。考虑到这个问题是毫无意义的。 – alternative 2014-10-30 19:54:06
有两个问题:
的
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
然后,您可以定义您的递归函数来检查相同长度的属性。
到目前为止给出的答案时至少一个列表列表是有限的,并且至少有一个是无限的效果不好:该功能无法终止,终止的时候是可能的,因为他们正忙着无限通话length
名单。下面是对任何类型的列表的问题的解答:
allSameLength :: [[a]] -> Bool
allSameLength [] = True
allSameLength xs = all null xs || all (not . null) xs && allSameLength (map tail xs)
这是一个非常简单的递归定义:要么所有的列表是空的,或者他们都不是空的,他们还是一样长,你拍照后从每个中排除一个元素。
你的函数应该有'[[a]] - > Bool'类型。 – Lee 2014-10-30 14:04:34
@Lee:这很有效,但为什么我不能''a] - > Bool'并将其应用于'Integer'或'String'列表中? – BullyWiiPlaza 2014-10-30 14:13:16
因为“整数”列表,例如'[Integer]'不是列表,每个元素都有'length'的概念。只有列表本身具有“长度”,因此如果要比较某些集合的长度,则需要一个列表集合:'[[a]]'。 – 2014-10-30 14:20:34