1

I'm quite new to Haskell and i'm not sure how to solve / approach this problem: I want a function with the type signature: [((Double, Double), Bool)] -> [[(Double, Double)]]. The function should only add (Double, Double) to the list of lists if Bool == True. If the bool is False, I want the (Double, Double) associated with the next True bool to be added to a new list. Consecutive (Double, Double)'s paired with Bool == True should be added to the same list. For example, an input of: [((1,1),True),((2,2), False),((3,3), False),((4,4),True),((5,5),True)] should return [[(1,1)],[(4,4),(5,5)]]. I did a little research and it seems like the groupBy function might be useful in solving the problem, but I'm not quite sure how to use it properly. As I'm new new to Haskell I'd prefer a more simple solution or explanation but any suggestions would help.

So far my code just creates a new list for every (Double, Double) associated with True bool. I'm not quite sure how to add to an existing list within a list.

consecTrue :: [((Double, Double),Bool)] -> [[(Double,Double)]]
consecTrue xs = case xs of
    [] -> []
    x:xs
        |snd x == True -> [fst x]:consecTrue xs
        |snd x == False -> consecTrue xs
4
  • 1
    This seems like a weird almost-duplicate of stackoverflow.com/q/58021470/625403. Commented Sep 21, 2019 at 2:09
  • 3
    @amalloy Yep. And this almost certainly means that both are homework. Commented Sep 21, 2019 at 2:30
  • 3
    Possible duplicate of Returning a list of lists with recursion Commented Sep 21, 2019 at 5:30
  • @amalloy this is of course a duplicate, but it is worded much better, so maybe close that other one as the duplicate of this one? Commented Sep 22, 2019 at 11:33

2 Answers 2

1

Yes, groupBy can be used. You will need the comparison function to feed groupBy, let's call it grf. Easiest path is probably to test the solution gradually within the interactive command, ghci.

$ ghci
Prelude> 
Prelude Data.List> import Data.List
Prelude Data.List> grf ((x1,y1),p1) ((x2,y2),p2) = (p1==p2)
Prelude Data.List> let lsa = [((1,1),True),((2,2), False),((3,3), False), ((4,4),True),((5,5),True)]
Prelude Data.List> 
Prelude Data.List> lsb = groupBy grf lsa
Prelude Data.List> lsb
[[((1,1),True)],[((2,2),False),((3,3),False)],[((4,4),True),((5,5),True)]]
Prelude Data.List> 


That's just a start. Then you need to get rid of the false ones, and then to get rid of the boolean values themselves.

Prelude Data.List> 
Prelude Data.List> lsc = filter (snd . head) lsb
Prelude Data.List> lsc
[[((1,1),True)],[((4,4),True),((5,5),True)]]
Prelude Data.List> 
Prelude Data.List> lsd = map (map fst) lsc
Prelude Data.List> lsd
[[(1,1)],[(4,4),(5,5)]]
Prelude Data.List> 
Prelude Data.List> 

Putting it all together:

import Data.List

consecTrue :: [((Double, Double),Bool)] -> [[(Double,Double)]]
consecTrue xs = let grf ((x1,y1),p1) ((x2,y2),p2) = (p1==p2)
                in  map (map fst) (filter (snd . head) (groupBy grf xs))

main = do
    let lsa = [((1,1),True),((2,2), False),((3,3), False),
              ((4,4),True),((5,5),True)]
    let res = consecTrue lsa

    putStrLn $ "input  = " ++ show lsa
    putStrLn $ "output = " ++ show res

That seems to do what you wanted:

input  = [((1.0,1.0),True),((2.0,2.0),False),((3.0,3.0),False),((4.0,4.0),True),((5.0,5.0),True)]
output = [[(1.0,1.0)],[(4.0,4.0),(5.0,5.0)]]
Sign up to request clarification or add additional context in comments.

3 Comments

Thank you - looks good. You did a good job of explaining each step; very clear and easy to follow.
What does does 'map' refer to?
@anon0987654321 Well, map is used to apply a given function to every element of a list, and return all the results as a new list. For example, if sq is the square function, the expression map sq [1, 3, 5] evaluates to the list: [1, 9, 25]. Defined here for example.
0

As a newcomer learning Haskell, not even yet knowing what map is, it makes total sense to have been asked to do this first of all by simple, direct recursion, creating a definition which stands on its own, not using any library functions.

And definition by simple direct recursion is just enumeration of possible cases we're presented with:

consecTrue :: [(t, Bool)] -> [[t]]
  -- empty list:
consecTrue [] = []
  -- list with exactly one entry in it:
consecTrue [(a,True)] = [[a]]
consecTrue [(a,False)] = []
  -- list with two or more entries in it:
consecTrue ((a1,True) : (a2, True) : more2)  =  (a1:r):q  where  
                                                    (r:q) = consecTrue ((a2,t2) : more2)
consecTrue ((a1,True) : (a2,False) : more2)  =  [a1] : consecTrue more2
consecTrue ((a1,False) : more1)              =  consecTrue more1

The (Double, Double) is immaterial, extraneous detail. Just t is enough, meaning anything can go there.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.