Alexia Desouza
Alexia Desouza

Reputation: 393

Haskell list with tuples

subject = [("maths",[]),("science",[]),("chemistry",[]),("french",[])]

marks = [("science","john"),("maths","john"),("chemistry","ron"),("maths","ron"),("maths","sam")]

output as

[("maths",["john","ron","sam"]),("science",["john"]),("chemistry",["ron"]),("french",[])]

my attempt:

nlist =  foldl'(\ (subjectname,studentname) (x,y) ->
                    if(x `elem` subjectname)
                        then (subjectname,studentname++[y])
                    else (subjectname,studentname)   ) subject marks

can anyone tell me what im doing wrong here. I'm getting error: parse error on input nlist

Upvotes: 2

Views: 159

Answers (2)

Long
Long

Reputation: 819

Write out the types! Here's an example of how I'd use types to construct the program. After that I'll show you how you can use types to fix your own program.

type Subject = String
type Person = String

insertOne :: (Subject, Person) -> [(Subject, [Person])] -> [(Subject, [Person])]

insertMany :: [(Subject, [Person])] -> [(Subject, Person)] -> [(Subject, [Person])]

subject :: [(Subject, [Person])]

marks :: [(Subject, Person)]

nlist = insertMany subject marks

Clearly you have already figured out

insertMany = foldr insertOne

It remains to implement insertOne:

insertOne (subject, person) =
  map (\(subject',list) -> if subject' == subject
                           then (subject', person:list)
                           else (subject', list))

Notice that writing out the types helps you to write a correct program. To see why your program is not valid, let's try to write out the types:

f :: (Subject, [Person]) -> (Subject, Person) -> (Subject, [Person])
f = (\ (subjectname,studentname) (x,y) ->
                if(x `elem` subjectname)
                    then (subjectname,studentname++[y])
                else (subjectname,studentname)   )
  1. x elem subjectname does not make sense, because subjectname is not a list of String. It should be x == subjectname, otherwise this is a fine function!
  2. foldl f would have type (Subject, [Person]) -> [(Subject, Person)] -> [(Subject, Person)]

This program is only capable of updating one subject, e.g.

foldl f ("maths",[]) marks == ("maths",["john","ron","sam"])

What you need now is to apply this to every subject, via map:

map (\x -> foldl f x marks) subject == [("maths",["john","ron","sam"]),("science",["john"]),("chemistry",["ron"]),("french",[])]

Upvotes: 4

Davislor
Davislor

Reputation: 15164

One problem is that you're passing a list of tuples to a function that expects a single tuple. What it appears you want to do is:

  • Look for an entry matching the subject in the accumulating association list
  • Get the list of students already in that subject (Or the empty list if no such association exists)
  • Create a new list of students with the current student's name added
  • Generate a new association consisting of the subject and the new list of students
  • Create a new association list with the new association replacing the old
  • Pass the new association list to the next iteration of the fold

Upvotes: 2

Related Questions