所有相同长度函数

问题描述:

我想写一个函数[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代替这个表达式编译。

+3

你的函数应该有'[[a]] - > Bool'类型。 – Lee 2014-10-30 14:04:34

+0

@Lee:这很有效,但为什么我不能''a] - > Bool'并将其应用于'Integer'或'String'列表中? – BullyWiiPlaza 2014-10-30 14:13:16

+3

因为“整数”列表,例如'[Integer]'不是列表,每个元素都有'length'的概念。只有列表本身具有“长度”,因此如果要比较某些集合的长度,则需要一个列表集合:'[[a]]'。 – 2014-10-30 14:20:34

实际上我们可以很简单地做到这一点。

sameLengths :: [[a]] -> Bool 
sameLengths [] = True 
sameLengths (x:xs) = all (\y -> length y == length x) xs 

无需任何递归 - 所有的长度是相同的当且仅当它们等于第一个,所以只提取第一和使用all轻松地检查休息。

至于为什么你不能定义为[a],请记住[String][[a]]以及[a]。但我们特别需要[[a]],因为无论a[a]length都必须定义。

+1

@ThreeFx oops固定,谢谢。最初我只想写'(==长度x)。长度“(我更喜欢),但认为最好是为清晰度编写明确的lambda – alternative 2014-10-30 16:03:14

+0

这对于像[[[],[1 ..]]这样的输入不起作用。 – amalloy 2014-10-30 18:47:55

+0

@amalloy我想我们只考虑有限长度,因为无限列表...是无限的,没有长度,所以你永远不会知道例如[[1 ..],[1 ..]]是否应该返回true或错误。考虑到这个问题是毫无意义的。 – alternative 2014-10-30 19:54:06

有两个问题:

  1. length功能定义在列表(length :: [a] -> Int),所以你 不能将其应用到其他类型的

  2. 你当然可以定义自己的类:

    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) 

这是一个非常简单的递归定义:要么所有的列表是空的,或者他们都不是空的,他们还是一样长,你拍照后从每个中排除一个元素。