对列表中的项目使用过滤器?

时间:2011-05-10 19:35:05

标签: list haskell filter

我正在尝试按列表中的项目进行过滤并逐行打印。这是我的代码:

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

为什么这不起作用?

2 个答案:

答案 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语句。它应该是相当不言自明的,您可以使用letwhere语句来定义“局部变量”。作为一个品味问题,我更喜欢放在哪里。

列出comprenensions与过滤器:列表推导可以像过滤器功能一样过滤列表。对于函数f :: a -> Bool和列表xs :: [a]

filter f xs[x | x <- xs, f x]相同。作为一种品味问题,我更喜欢在这种情况下拼写filter,因为它清楚地表明我正在过滤列表。

另见LYAH # Maps and filters

-

进一步推荐:使用记录语法

而不是

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
  • 等等

另见LYAH # Record syntax

答案 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中执行时会导致打印的事情。看起来这很难理解,但很快你就会明白。