2014-02-24 84 views
1

我有一個自定義的數據類型Movie = String Int [(String,Int)](電影名年[(風扇,評級)的列表中的內容,並希望做兩件事情:1.4.3自定義數據類型

首先,我想使從元組的列表平均值的INTS,只是輸出一個數的函數到目前爲止,我有這個不完整的功能:

avgRating :: [DataType] -> Int avgRating [(Movie a b [(fan,rating)])] = sumRatings/(length [<mylist>])

在這裏,我需要一個函數sumRatings列表以遞歸,總結所有評級,但我不知道從哪裏開始。

我在這裏的另一個問題是,我不知道要把<mylist>放在哪裏,因爲我通常會給該列表一個變量名稱,然後在那裏使用它,但是由於我已經將列表拆分以定義其他變量,我無法命名它。

我希望有道理,謝謝。也

avgRating [(Movie a b [email protected][(fan, rating)])] = … 

需要注意的是,如果你不打算使用,你解壓的變量,它的哈斯克爾:

回答

4

我猜你有一個數據結構定義爲

data Movie = Movie String Int [(String, Int)] 

雖然這個工作,它可以是一個有點麻煩與當你有很多領域的工作。相反,你可以利用類型別名和記錄語法作爲

type Name = String 
type Year = Int 
type Rating = Int 

data Movie = Movie 
    { mName :: Name 
    , mYear :: Year 
    , mRatings :: [(Name, Rating)] 
    } deriving (Eq, Show) 

現在事情更加明確,更容易處理。 mName,mYearmRatings函數將採取Movie並從中返回相應的字段。你的Movie構造函數仍然以相同的方式工作,所以它不會破壞現有的代碼。

要計算評分的平均值,真要提取的電影所有的評級,並將其聚合成列表的功能:

ratings :: Movie -> [Rating] 
ratings mov = map snd $ mRatings mov 

然後你只需要一個average功能。這將是一個有點不同,因爲你無法計算的Int小號直接的平均水平,你就必須轉換爲浮點類型:

average :: [Rating] -> Float -- Double precision isn't really needed here 
average rs = fromIntegral (sum rs)/fromIntegral (length rs) 

fromIntegral功能轉換的IntFloat(實際類型簽名有點更一般)。由於IntsumInt而列表的length總是Int,所以您需要將兩者都轉換。

現在你只需撰寫這些成一個單一的功能:

movieAvgRating :: Movie -> Float 
movieAvgRating = average . ratings 

現在,如果你需要計算的平均收視率幾部電影,你可以申請ratings他們每個人,他們聚集到一個單一的收視率列表,然後致電average。我建議看看concatMap函數。你會想要做像

moviesAvgRating :: [Movie] -> Float 
moviesAvgRating movs = average $ ??? 
+0

嗨,謝謝你的迴應!我只會問到目前爲止的部分:這些{}與其他括號有什麼不同?與評分相伴的名字是球迷的名字,所以我認爲我會添加一個新的類型Fan = String並且使mRatings :: [(Fan,Rating)]? – Chillo

+0

@Chillo大括號表示[記錄語法](http://learnyouahaskell.com/making-own-own-types-and-typeclasses),它只是一種命名構造函數字段的方法。如果你願意,你當然可以編寫另一個'type Fan = String',這是完全可以接受的。 – bheklilr

+0

函數movieAvgRating = average。收視率讓我有點困惑,你如何指定正在評級的電影?它不會看起來像'movieAvgRating mov = average(ratings mov)'?由於評分功能需要電影輸入。另外,這個功能是什麼。運營商服務? – Chillo

1

先回答你的第二個問題,你可以綁定到一個變量,解壓縮後同時使用@約定將其綁定到_

avgRating [(Movie _ _ [email protected][(fan, rating)])] = … 

這有助於讀者重點放在什麼實際上是非常重要的。

我不想只給你解決你的遞歸問題,因爲學習編寫遞歸函數是Haskell編程的一個重要且有益的部分。 (如果你真的想讓我爲你破壞它,請在評論中告訴我。)然而,基本思想是你需要考慮兩種不同的情況:基本情況(遞歸停止)和遞歸情況。作爲一個例子,考慮內置sum功能:

sum :: Num a => [a] -> a 
sum [] = 0 
sum (x:xs) = x + sum xs 

這裏,基本情況是,當sum得到一個空表 - 它只是計算結果爲0。在遞歸的情況下,我們假設sum已經可以生產一個較小的清單的總和,我們將其擴大到一個更大的清單。

如果您在遞歸過程中遇到問題,Harold Abelson和Gerald Jay Sussman在1996年出版的MIT Press(Cambridge)上第Structure and Interpretation of Computer Programs號第二版中對該主題進行了詳細討論。 21(§§1.1.7–1.2)。它在Scheme中,不是Haskell,但是語言非常相似 - 至少在這個概念層面上 - 每個語言都可以作爲另一個體面的模型。

+0

功能不,我不想遞歸寵壞了我,但它的哈斯克爾我發現最難收拾的一部分。感謝您的回覆,只要看一下總和功能就是幫助我將它拼湊在一起。 – Chillo