Reputation: 119
The end goal is to get a list of ratings such that no same user should be duplicated in the list. Therefore you cannot have "Emma" rating twice.
Data and Tuple defined as:
type Rating = (String, Int)
data Film = Film { title :: String,
director :: String,
year :: Int,
ratings :: [Rating] } deriving (Read,Show)
old function defined as (Which works):
newRatings :: [Rating] -> Rating -> [Rating]
newRatings oldRatings (newUser,newRate) = [(user,rate) | (user,rate) <- oldRatings, user /= newUser] ++ [(newUser,newRate)]
creating a better function defined as:
newRating :: Rating -> [Rating] -> [Rating]
newRating (newUser,newRate) = ((newUser,newRate): ) . filter(((map fst ratings)/= newUser). ratings)
I don't understand where I am going wrong. My understanding of the function is. -> Get the rating and compare it the an old list of ratings to check if the users match. If they do, don't include their specific rating and carry on passing list until empty. Then append the new rating to the list.
Could someone explain where I am going wrong?
The Error I'm getting:
v3.hs:104:63:
Couldn't match expected type ‘[Rating] -> Bool’
with actual type ‘Bool’
In the first argument of ‘(.)’, namely
‘((map fst ratings) /= newUser)’
In the first argument of ‘filter’, namely
‘(((map fst ratings) /= newUser) . ratings)’
In the second argument of ‘(.)’, namely
‘filter (((map fst ratings) /= newUser) . ratings)’
v3.hs:104:72:
Couldn't match expected type ‘[(Char, b0)]’
with actual type ‘Film -> [Rating]’
Probable cause: ‘ratings’ is applied to too few arguments
In the second argument of ‘map’, namely ‘ratings’
In the first argument of ‘(/=)’, namely ‘(map fst ratings)’
v3.hs:104:93:
Couldn't match type ‘(String, Int)’ with ‘Film’
Expected type: Rating -> [Rating]
Actual type: Film -> [Rating]
In the second argument of ‘(.)’, namely ‘ratings’
In the first argument of ‘filter’, namely
‘(((map fst ratings) /= newUser) . ratings)’
Upvotes: 1
Views: 871
Reputation: 91837
First: when asking why something ins't working, please provide a paste of what is actually happening: you would get better help more quickly if you included the compiler error message, so prospective answerers don't have to copy and paste your code to see what's wrong.
The first thing that jumps out at me is that
(map fst ratings)/= newUser
doesn't look well-typed at all: newUser
is a String, so it can't possibly be equal to (map fst ratings)
, a list of strings. You want something more like:
filter ((newUser /=) . fst) . ratings
Another problem is that you've made this point-free: that's cool sometimes, but here I think it's making it a lot harder to read. It's much simpler to write like this:
uniquify :: [Rating] -> [Rating]
uniquify [] = []
uniquify (rate@(newUser,_):more) = rate : uniquify (filter ((newUser /=) . fst) more)
But better still is to find an appropriate built-in function, and in this case that's Data.List.nubBy
, combined with Data.Function.on
:
uniquify' :: Eq a => [(a,b)] -> [(a,b)]
uniquify' = nubBy ((==) `on` fst)
That's a more general type, which you can specialize to the type given to uniquify
, and a lot simpler to implement.
Upvotes: 2