我试图迭代自定义数据类型列表,并确定特定类型的值.在这种情况下,我想要列表中的年龄:
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
Run Code Online (Sandbox Code Playgroud)
错误:
"Age is applied to too few arguments"
Run Code Online (Sandbox Code Playgroud)
什么是最好的解决方案?
你真的不能x == Age......没有意义.您只能与x其他类型的值进行比较MyData,例如Age 10,或DOB 40,或Name "John". Age没有类型MyData......它有类型Int -> MyData.
您可以使用case语句检查值的构造函数:
myFunction :: [MyData] -> MyData
myFunction (x:xs) = case x of
Age _ -> ...
DOB _ -> ...
Name _ -> ...
Address _ -> ...
Run Code Online (Sandbox Code Playgroud)
或者,如果您只关心Age构造函数,则可以使用通配符:
myFunction :: [MyData] -> MyData
myFunction (x:xs) = case x of
Age _ -> ...
_ -> ...
Run Code Online (Sandbox Code Playgroud)
另请注意,您可能实际上想要返回a [MyData]而不是a MyData.
对于它的价值,一个更好的方法来编写这个函数可能是
myFunction :: [MyData] -> [MyData]
myFunction xs = [ x | x@(Age _) <- xs ]
Run Code Online (Sandbox Code Playgroud)
或者你可以使用更高阶函数而不是显式递归,这往往更容易出错:
myFunction :: [MyData] -> [MyData]
myFunction = mapMaybe (\x -> case x of Age _ -> Just x; _ -> Nothing)
Run Code Online (Sandbox Code Playgroud)
编辑:请注意您在问题中使用的语言 - 所有值都x具有相同的类型,在这里 - MyData. Age 10与...有相同的类型DOB 40.它们都是相同类型的值,只是使用不同的构造函数创建的.因此,这不会过滤某个类型的值的列表 - 它会过滤某个构造函数创建的值.