2013-10-06 42 views
1

我一直在與這個問題爭鬥了一段時間。我試圖創建一個「組織」,這是一個健身房列表。這些健身房是人的名單。每個人都有一個身份證號碼,年齡和信用額度。基本Haskell:通過多個列表搜索相同的元素

我希望FindID函數能夠搜索整個組織以搜索健身房列表,找到具有輸入ID的用戶,然後返回他們的信用總額。但是,我覺得我正在過度地糾正這個問題,現在我真的很掙扎。

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) 
+0

我很確定這段代碼不能編譯。例如。如何定義「validGym」和「market」? – Philipp

+0

對不起,我複製了另一個示例中的代碼,並且在將它放在此處時忘記進行更改。現在改變了。 – John

回答

1

首先,我會建議使用記錄來表示你的人,除非你有特別的理由指定一個新的類型,每個字段:

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] 

接下來,你可以使用map轉換Gym轉換成[Int]personId,然後您可以使用內置的elem來檢查給定的ID是否出現在該列表中。

hasPerson :: Gym -> ID -> Bool 
hasPerson gym pId = pId `elem` map personId gym 

現在,對於findID功能,我會建議它改名爲類似organizationCredit,我會做一個簡單的函數調用gymCredit來計算的話單個健身房:

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 

另外,你可以聲明你的功能

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 

編輯:堅持使用舊的類型,你只需要自己定義一些額外的功能,然後把它們在你的代碼,你需要

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 

重要的是要注意,我已經添加Eq到每種新類型的派生類型類列表。沒有它,你將無法直接比較兩個ID,你必須首先提取這些值。另一個重要的類型是Ord,它允許您使用<,>,<=>=運算符,以及一大堆列表函數,如sort

+0

lambda可以寫成'(pId ==)。 personId'。 – Philipp

+0

@ Philipp它可以,我會在我的代碼中使用它,但lambda函數對於初學者來說可以更容易理解 – bheklilr

+0

哇!非常感謝這看起來很有前途,但你能解釋一下這一行請問: (\ p - > personId p == pId) 它明顯地將p與pID進行比較,並返回一個布爾值,但\ p - > personId做了什麼? – John