简体   繁体   中英

Filter tuples in list of lists [Haskell]

I have a list of lists of tuples:

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))]]

I would like to filter them by the first value of each tuple. That's what I tried...

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

with

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

That's the error I got:

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.

How can I solve this? Thanks!

Let's take a few steps to simplify the compute function and figure out the problem:

  1. First of all, [row | row <- list] [row | row <- list] does nothing, it's equivalent to just list , so we can remove it and replace it with list , to make the function easier to read:

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

    By the way, in your message I see that list isn't what the argument to filter is actually called. Instead, it's a checkAround m (x, y) , so compute should probably look like this:

     compute m (x,y) = filter (\\(a,(_,_)) -> a /= 1) $ checkAround m (x, y) 
  2. The function you're passing to filter is unnecessarily complicated, we can replace it with \\(a,_) -> a /= 1 or even (/=1) . fst (/=1) . fst to make it less noisy. Doing that gives us:

     compute m (x,y) = filter ((/=1) . fst) list 
  3. I'd say it's now much easier to see the problem. Your list has the type [[(Int, (Int, Int))]] , ie. it's a list of lists of tuples.

    But the predicate your passing into filter is expecting a tuple, therefore filter itself is expecting a list of tuples.

    This is an obvious type mismatch. How do we solve this? I don't know, that's up to you, but I guess you want to filter the inner list.

    How do we do this? Well, we need to go through each of the inner lists, filter them and put the filtered ones in a new list. This is exactly what map (or fmap ) can help us with. Let's map the filter we've constructed over list :

     compute m (x,y) = map (filter ((/=1) . fst)) list 
  4. Unfortunately, the above still gives us a type error:

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

    Well, why is that? We know that the Actual type is the type of list and the type of the filtered list as well, but what is the Expected type and why is it a [[Int]] ?

    The answer lies in your type signature, Matrix -> Coordinates -> Matrix . compute is supposed to produce a list of lists of Int s, but we're filtering something a bit different.

At this point I don't really know what you'd like to do, so I'll just end here, but I suspect you either need to change compute 's type signature or you need to somehow merge m with the filtered results to create a new matrix.

Is this what you are trying to do?

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]

Even if your list is not some kind of oddly structured sparse matrix representation, I think the final result is what you described.

Problem 1: Your definition of compute refers to list , but list is not a parameter.

Problem 2: If you change list to m your code is correct, but the type signature you gave is not correct.

Solution:

Change list to m , and don't give a type a signature:

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

Now ask ghci what the type signature should be:

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

Now you see that that type Matrix should be defined as

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM