在列表列表中过滤元组[Haskell]

时间:2016-06-24 10:24:03

标签: list haskell

我有一个元组列表列表:

let list = [[(1,(2,2)),(0,(3,2)),(0,(4,2))],[(0,(2,3)),(0,(3,3)),(0,(4,3))],[(0,(2,4)),(0,(3,4)),(0,(4,4))]]

我想按每个元组的第一个值过滤它们。 这就是我试过的......

compute :: Matrix -> Coordinates -> Matrix
compute m (x,y) = filter (\(a,(_,_)) -> a /= 1) [row | row <- list]

type Matrix = [[Int]]
type Coordinates = (Int, Int)

这是我得到的错误:

ContiguousRegion.hs:20:36:
Couldn't match expected type ‘[Int]’
            with actual type ‘(Integer, (t0, t1))’
In the pattern: (a, (_, _))
In the first argument of ‘filter’, namely
  ‘(\ (a, (_, _)) -> a /= 1)’
In the expression:
  filter
    (\ (a, (_, _)) -> a /= 1) [row | row <- checkAround m (x, y)]

ContiguousRegion.hs:20:58:
Couldn't match type ‘(Int, (Int, Int))’ with ‘Int’
Expected type: [Int]
  Actual type: [(Int, (Int, Int))]
In the expression: row
In the second argument of ‘filter’, namely
  ‘[row | row <- checkAround m (x, y)]’
Failed, modules loaded: none.

我该如何解决这个问题? 谢谢!

3 个答案:

答案 0 :(得分:4)

让我们采取一些步骤来简化compute函数并找出问题所在:

  1. 首先,[row | row <- list]不执行任何操作,它只相当于list,因此我们可以删除它并将其替换为list,以使该功能更易于阅读:

    compute m (x,y) = filter (\(a,(_,_)) -> a /= 1) list
    

    顺便说一下,在你的消息中,我看到list不是实际调用过滤器的参数。相反,它是checkAround m (x, y),因此compute应该看起来像这样:

    compute m (x,y) = filter (\(a,(_,_)) -> a /= 1) $ checkAround m (x, y)
    
  2. 您传递给filter的功能不必要地复杂,我们可以将其替换为\(a,_) -> a /= 1甚至(/=1) . fst,以减少噪音。这样做可以让我们:

    compute m (x,y) = filter ((/=1) . fst) list
    
  3. 我说现在看到这个问题要容易得多。您的list类型为[[(Int, (Int, Int))]],即。它是元组列表的列表。

    但是你传入filter的谓词期待一个元组,因此filter本身就是期待一个元组列表。

    这是明显的类型不匹配。我们如何解决这个问题?我不知道,这取决于你,但我想你想要过滤内部列表。

    我们怎么做?好吧,我们需要遍历每个内部列表,过滤它们并将过滤后的列表放入新列表中。这正是map(或fmap)可以帮助我们的内容。让我们映射我们在list上构建的过滤器:

    compute m (x,y) = map (filter ((/=1) . fst)) list
    
  4. 不幸的是,上面仍然给出了类型错误:

    Couldn't match type ‘(Integer, (Integer, Integer))’ with ‘Int’
    Expected type: [[Int]]
    Actual type: [[(Integer, (Integer, Integer))]]
    

    那么,为什么呢?我们知道Actual typelist的类型以及已过滤列表的类型,但Expected type是什么,为什么它是[[Int]]

    答案取决于您的类型签名Matrix -> Coordinates -> Matrixcompute应该会生成Int个列表的列表,但我们会过滤一些不同的内容。

  5. 此时我真的不知道你想做什么,所以我会在这里结束,但我怀疑你需要改变compute的类型签名,或者你需要以某种方式将m与过滤后的结果合并以创建新矩阵。

答案 1 :(得分:0)

这是你想要做的吗?

type SparseMatrix = [Row]
type Row = [Element]
type Element = (Int, Coordinates)
type Coordinates = (Int, Int)

removeRowVal :: Row -> Int -> Row
removeRowVal row i = filter ((/= i).fst) row

removeSMVal :: SparseMatrix -> Int -> SparseMatrix
removeSMVal sm i = [removeRowVal row i | row <- sm]

即使你的list不是某种奇怪结构的稀疏矩阵表示,我认为最终的结果就是你所描述的。

答案 2 :(得分:0)

问题1:您对compute的定义是list,但list不是参数。

问题2:如果您将list更改为m,那么您的代码是正确的,但您提供的类型签名不正确。

解决方案:

list更改为m,并且不为类型提供签名:

compute m (x,y) = filter (\(a,(_,_)) -> a /= 1) [row | row <- m]

现在问ghci类型签名应该是什么:

ghci> :t compute
compute
    :: (Eq a, Num a) => [(a, (t2, t3))] -> (t, t1) -> [(a, (t2, t3))]

现在你看到type Matrix应该定义为

type Matrix = [ (Int, (Int,Int) ]