Reputation: 667
I've been battling with this problem for a while. I'm trying to create an "organisation" which is a list of Gyms. These gyms are a list of People. Each person has an ID number, an age and an amount of credit.
I want the FindID function to search through the organisation to search through the list of Gyms to find the users with the inputted ID and then return the total of their credit. However, I feel I'm overcomplcating the problem and I am really struggling now.
newtype ID = ID Int deriving (Show)
newtype Age = Age Int deriving (Show)
newtype Credit = Credit Int deriving (Show)
newtype Person = Person (ID, Age, Weight) deriving (Show)
type Gym = [Person]
type Organisation = [Gym]
getAge :: Person -> Int
getAge (Person(a,Age b,c)) = b
getID :: Person -> Int
getID (Person(ID a,b,c)) = a
getCredit :: Person -> Int
getCredit (Person(a,b,Credit c)) = c
p = Person ( ID 123, Age 65, Credit 12000)
q = Person ( ID 321, Age 64, Credit 0)
e = Person ( ID 453, Age 30, Credit 3000)
r = Person ( ID 123, Age 65, Credit 2310)
s = Person ( ID 364, Age 32, Credit 32340)
t = Person ( ID 123, Age 65, Credit 1300)
org1 = [p,q,e]
org2 = [r,s,t]
hasPerson :: Gym->Int-> Bool
hasPerson gym' id' = not (null(filter hasperson' gym') )
where
hasperson' person' = getID person' == id'
findID:: ID -> Organisation -> Int
findID id' org = total
where
IsInGym org' = hasPerson ( org' id' )
validGym = filter (IsInGym) org'
total = sum ( map getCredit validGym)
Upvotes: 1
Views: 304
Reputation: 54058
First, I would recommend using a record to represent your person, unless you have a particular reason to assign a new type to each field:
type ID = Int
type Age = Int
type Credit = Int
data Person = Person
{ personId :: ID
, personAge :: Age
, personCredit :: Credit
} deriving (Eq, Show)
type Gym = [Person]
type Organization = [Gym]
Next, you can use map
to convert a Gym
into [Int]
with personId
, then you can use the built-in elem
to check if the ID given appears in that list.
hasPerson :: Gym -> ID -> Bool
hasPerson gym pId = pId `elem` map personId gym
Now, for the findID
function, I would suggest renaming it to something like organizationCredit
, and I would make a simpler function called gymCredit
to calculate it for a single gym:
gymCredit :: ID -> Gym -> Credit
gymCredit pId gym = sum $ map personCredit $ filter (\p -> personId p == pId) gym
organizationCredit :: ID -> Organization -> Credit
organizationCredit pId org = sum $ map (gymCredit pId) org
Alternatively, you could declare your functions as
gymCredit :: Person -> Gym -> Credit
gymCredit person gym = sum $ map personCredit $ filter (\p -> personId p == pId) gym
where pId = personId person
organizationCredit :: Person -> Organization -> Credit
organizationCredit person org = sum $ map (gymCredit person) org
EDIT: To stick with your old types, you just have to define a few extra functions yourself, then put them in your code where you need to
newtype ID = ID Int deriving (Eq, Show)
newtype Age = Age Int deriving (Eq, Show)
newtype Credit = Credit Int deriving (Eq, Show)
newtype Person = Person (ID, Age, Credit) deriving (Eq, Show)
type Gym = [Person]
type Organisation = [Gym]
personId :: Person -> ID
personId (Person (i, a, c)) = i
personAge :: Person -> Age
personAge (Person (i, a, c)) = a
personCredit :: Person -> Credit
personCredit (Person (i, a, c)) = c
idVal :: ID -> Int
idVal (ID x) = x
ageVal :: Age -> Int
ageVal (Age x) = x
creditVal :: Credit -> Int
creditVal (Credit x) = x
gymCredit :: Person -> Gym -> Credit
gymCredit person gym = Credit $ sum $ map (creditVal . personCredit) $ filter (\p -> personId p == pId) gym
where pId = personId person
organisationCredit :: Person -> Organisation -> Credit
organisationCredit person org = Credit $ sum $ map (creditVal . gymCredit person) org
It is important to note that I've added Eq
to the list of derived typeclasses for each newtype. Without it, you wouldn't be able to directly compare two ID
s, you'd have to extract the values first. Another important typeclass to derive is Ord
, which lets you use the <
, >
, <=
, and >=
operators, as well as a whole bunch of list functions like sort
.
Upvotes: 1