我正在尝试按列表中的项目进行过滤并逐行打印。这是我的代码:
data Car = Car String [String] Int [String]
testDatabase :: [Car]
testDatabase = [Car"Casino Royale" ["Daniel Craig"] 2006 ["Garry", "Dave", "Zoe", "Kevin", "Emma"],Car"Blade Runner" ["Harrison Ford", "Rutger Hauer"] 1982 ["Dave", "Zoe", "Amy", "Bill", "Ian", "Kevin", "Emma", "Sam", "Megan"]]
formatCarRow (Car a b c d) = show a ++ " | " ++ concat [i ++ ", " | i <- init b] ++ last b ++ " | " ++ show c ++ " | " ++ concat [j ++ ", " | j <- init d] ++ last d
displayFilmsByYear :: String -> IO [()]
displayFilmsByYear chosenYear = mapM (putStrLn.formatFilmRow) [putStrLn(filter ((== chosenYear).y)) | (w x y z) <- testDatabase] -- This is the code not working i think
为什么这不起作用?
答案 0 :(得分:5)
如果您想过滤列表,我建议使用filter
功能:)
data Car = Car String [String] Int [String]
year :: Car -> Int
year (Car _ _ y _) = y
filterByYear :: Int -> [Car] -> [Car]
filterByYear chosenYear cars = filter (\car -> year car == chosenYear) cars
showCar :: Car -> String
showCar car = undefined -- you can implement this how you like
displayCarsByYear :: Int -> IO ()
displayCarsByYear chosenYear = mapM_ (putStrLn . showCar) filteredCars
where filteredCars = filterByYear chosenYear testDatabase
在这里解释一些事情似乎是明智的:
匿名函数:(\car -> year car == chosenYear)
是一个匿名函数。它需要一个参数并将其称为car
。然后它确定该车的年份是否等于chosenYear
。我没有明确写出这个函数的类型签名,但它是Car -> Bool
。
过滤:我将该功能提供给filter
,以便查看Car
列表。当filter
找到该函数返回True
的汽车时,它会将它们放入结果列表中。 False
结果意味着汽车无法通过过滤器。
功能组合:(putStrLn . showCar)
这是首先执行showCar
的功能,然后对putStrLn
的结果使用showCar
。< / p>
位置:您会在代码末尾看到where
语句。它应该是相当不言自明的,您可以使用let
或where
语句来定义“局部变量”。作为一个品味问题,我更喜欢放在哪里。
列出comprenensions与过滤器:列表推导可以像过滤器功能一样过滤列表。对于函数f :: a -> Bool
和列表xs :: [a]
filter f xs
与[x | x <- xs, f x]
相同。作为一种品味问题,我更喜欢在这种情况下拼写filter
,因为它清楚地表明我正在过滤列表。
-
进一步推荐:使用记录语法
而不是
data Car = Car String [String] Int [String]
为什么不
data Film = Film { name :: String
, actors :: [String]
, released :: Int
, characters :: [String]
}
(我真的不知道你的最后一个字符串列表是什么)
通过这种方式,你可以构建一个像这样的电影:
lotr :: Film
lotr = Film { name = "Lord of the Rings"
, actors = ["Elijah Wood", "Ian McKellen", "Orlando Bloom"]
, released = 2001
, characters = ["Frodo", "Sam", "Pippin", "Merry"]
}
您自动拥有访问者功能
released :: Film -> Int
name :: Film -> String
答案 1 :(得分:4)
重点是:
[putStrLn(filter ((== chosenYear).y)) | (w x y z) <- testDatabase]
你还没有理解列表理解。 你想要的是:
[ (Car w x y z) | (Car w x y z) <- testDatabase, y==choosenYear]
可能。
使用
mapM (putStrLn . formatCarRow)
您已订购:格式,然后打印下列列表中的每个元素。因此,列表理解中的putStrLn是完全荒谬的。
请注意,putStrLn在某种程度上是用词不当:它实际上不会打印任何东西!它只是构造了一个在IO monad中执行时会导致打印的事情。看起来这很难理解,但很快你就会明白。