4

我在 Haskell 中有一个 2D 列表[[Int]],我想检查两件事:

  1. 列表是否具有与列相同的行数
  2. 行是否具有相同数量的元素

例如:

[[1,2,3], [1,55,9]]具有与列相同的行数 - 这里为 2 - 每行具有相同数量的元素,即 3。

[[1,2], [1,55], [4,7]]尽管行数和列数不相等,即 3r 2c,但每行中的元素数相同。

另一个例子:

[[1,2], [1,55], [4,7,8]]行数与列数都不相同,每行的元素数也不相同。

实际上第1步包括第2步,对吗?

我的尝试:

所以到目前为止我尝试的是:

listIsEqual :: [[Int]] -> Bool
listIsEqual myList = (all (\x -> length x == (length myList)) )

现在我收到以下错误消息:

Couldn't match expected type `Bool' with actual type `[a0] -> Bool'
In the return type of a call of `all'
Probable cause: `all' is applied to too few arguments
In the expression: (all (\ x -> length x == (length myList)))
In an equation for `listIsEqual':
            listIsEqual myList = (all (\ x -> length x == (length myList)))

谁能告诉我问题出在哪里?

还有其他方法可以解决这个问题吗?

4

3 回答 3

6

GHC 的错误消息并不总是最有帮助的,但在这种情况下它是正确的。

可能的原因:“all”应用于太少的参数

确实,您忘记了第二个参数all

listIsEqual myList = all (\x -> length x == length myList) myList
                                                           ^^^^^^
于 2013-05-07T10:32:51.297 回答
3

对于第二个任务,您可以映射定义函数的每一行的长度(该行中的列数)

let columnLengths rows = map length rows
Prelude> columnLengths [[1,2], [1,55], [4,7,8]]
[2,2,3]

现在我们有了一个包含列长度的列表,我们必须检查它们是否都相等。中的函数从列表nubData.List删除重复项。

let columnsLengthEqual = (==) 1 . length . nub . columnLengths

或者一起

let columnsLengthEqual = (==) 1 . length . nub . map length
于 2013-05-07T10:32:44.420 回答
0

尊重您的标准的矩阵是平方矩阵,然后检查第一个行的长度的平方是否等于元素的数量应该没问题。

isSquaredMatrix xs@(h:_)  = ((^2) . length $ h) == (length . concat $ xs) 
isSquaredMatrix _         =  True 

但正如 hammar 所指出的,这是不正确的,因为我们可以使用错误的输入获得积极的结果。

# isSquaredMatrix [[1,2,3],[4,5],[6,7,8,9]]
True -- But this is false  

@约翰,

@当我们想要引用整个类型的同时我们已经分解它时,我们会使用模式匹配。一个例子应该给你更多的洞察力,

通常我们可以使用模式匹配定义一个详尽的函数,如下所示。

actOnList []     = -- do something when we encounter an empty list
actOnList (x:xs) = -- do something with h, and do another stuff with xs  

例如,

actOnList [] = []
actOnList (x:xs) = 
    if (pred x)
    then x:xs
    else actOnList xs

在这里,我的函数消耗列表,直到满足谓词。
我们可以想象 skipUntilMeetAChar

skipUntilMeetAChar :: [Char] -> Char -> [Char]
skipUntilMeetAChar []  c    = []
skipUntilMeetAChar (x:xs) c = 
    if (x==c)
    then x:xs
    else actOnList xs c

正如您所看到的,当遇到 char 时,我们希望返回列表,而不仅仅是 tail,然后我们需要使用 headx和 tail重建我们的列表xs。这可以通过使用来克服@

skipUntilMeetAChar :: String -> Char -> String
skipUntilMeetAChar []  c    = []
skipUntilMeetAChar l@(x:xs) c = 
    if (x==c)
    then l 
    else actOnList xs c

现在,关于 ($) 运算符,这又是一些语法糖。
由于函数应用程序是左关联的,这导致我们广泛使用括号来重新排序函数的应用程序,如下例所示。

# f3 (f2 (f1 (f0 x)))

然后为了避免管理右括号的痛苦,$引入了美元运算符,然后我们之前的表达式变成了。

# f3 $ f2 $ f1 $ f0 x

这绝对更具可读性和最容易编写。

请注意,此运算符定义如下。

($) :: (a -> b) -> a -> b  
f $ x = f x  

我建议您参考以下介绍材料了解更多信息。

于 2013-05-07T11:57:28.043 回答