2016-09-25 35 views
0

我試圖迭代自定義數據類型的列表,以及確切的特定類型的值。在這種情況下,我想年齡從列表:基於類型從列表中提取值?

data MyData = Age Int | DOB Int | Name String | Address String 

myList = [Age 89, DOB 13, Age 33, Name "Barbra", Address "103 Lane"] 

myFunction :: [MyData] -> MyData 
myFunction (x : xs) = if x == Age then x : myFunction xs else myFunction xs 

錯誤:

"Age is applied to too few arguments" 

請告訴我這種情況的最佳解決方案?

回答

5

你不可能真的有x == Age ......這是沒有道理的。您只能比較x與其他MyData類型的值,如Age 10DOB 40Name "John"Age沒有類型MyData ...它有類型Int -> MyData

可以檢查值有什麼構造函數通過使用case語句:

myFunction :: [MyData] -> MyData 
myFunction (x:xs) = case x of 
         Age _  -> ... 
         DOB _  -> ... 
         Name _ -> ... 
         Address _ -> ... 

或者,如果你只關心Age構造,可以通配符一切:

myFunction :: [MyData] -> MyData 
myFunction (x:xs) = case x of 
         Age _ -> ... 
         _  -> ... 

還要注意,你可能實際上想要返回[MyData],而不是MyData

對於它的價值,寫這個功能的更好的方式可能是

myFunction :: [MyData] -> [MyData] 
myFunction xs = [ x | [email protected](Age _) <- xs ] 

或者你可以使用一個高階函數,而不是明確的遞歸,這往往是更容易出現錯誤的:

myFunction :: [MyData] -> [MyData] 
myFunction = mapMaybe (\x -> case x of Age _ -> Just x; _ -> Nothing) 

編輯:小心你使用在這裏討論的語言 - 的x所有值具有相同,在這裏 - MyDataAge 10DOB 40具有相同的類型。它們都是相同類型的值,只是使用不同的構造函數創建的。因此,這不會篩選特定類型值的列表 - 它將篩選某個構造函數創建的值。

+0

在一個命令式的lang中,像C++一樣,一些編譯器會將'x == Age'解釋爲'x是Age'類型的,這就是方法背後的瘋狂...... –

+1

我不認爲這是屬性命令式語言:o這就是語言如何處理'==',但這不是一個特別重要的事情。可能與函數式語言中的可能性一樣:) –

+0

另外,請記住,'x'永遠不是'Age'類型',因爲'Age'不是一種類型。 'x'總是類型爲'MyData'。 –