type UserRating = (String, Int)
data Film = Film
{ title :: String
, director :: String
, year :: Int
, userRatings :: [UserRating]
} deriving ( Show )
testDatabase :: [Film]
testDatabase = [Film "Blade Runner" "Ridley Scott" 1982 [("Amy",6), ("Bill",9), ("Ian",7), ("Kevin",9), ("Emma",4), ("Sam",5), ("Megan",4)],
Film "The Fly" "David Cronenberg" 1986 [("Megan",4), ("Fred",7), ("Chris",5), ("Ian",0), ("Amy",5)]]
averageRating ::[UserRating] -> Float
averageRating rating = fromIntegral (sum [b|(a,b) <- rating])/fromIntegral (length rating)
showAllFilms :: [Film] -> String
showAllFilms [] = []
showAllFilms (x:xs) = printf "%s %s d %3.1f\n" (title x) (director x) (year x) (averageRating(userRatings x)) ++ showAllFilms xs
我需要在不使用任何I / O功能的情况下将列表分割为新行,这可能吗?大多数解决方案使用putStr,但这是一个I / O功能。我是Haskell的新手,任何帮助都会受到赞赏。
答案 0 :(得分:1)
问题是你想看
> showAllFilms testDatabase
Blade Runner Ridley Scott 1982 5.0
The Fly David Cronenberg 1986 4.3
(我只是制作了平均评分)
但相反,你正在看
> showAllFilms testDatabase
"Blade Runner Ridley Scott 1982 5.0\nThe Fly David Cronenberg 1986 4.3\n
这是因为当您在GHCi中评估函数时,会自动打印输出。如果您要输入
> testDatabase !! 0
你会看到第一个Film
格式良好的非字符串输出,但是幕后发生的事情是GHCi真的在运行
print $ testDatabase !! 0
相当于
putStrLn . show $ testDatabase !! 0
因此,如果您希望\n
呈现为新行并且您希望输出中不存在引号,则有来打印它。您可以通过
> "test\n"
"test\n"
> show "test\n"
"\"test\\n\""
> putStrLn $ show "test\n"
"test\n"
> putStrLn "test\n"
test
>
另一种方法是不导出Show
实例,而是执行以下操作:
instance Show Film where
show (Film t d y rs) = printf "%s %s d %3.1f" t d y (averageRating rs)
showList films s = unlines (map show films) ++ s
然后在GHCi中,
> testDatabase
Blade Runner Ridley Scott 1982 5.0
The Fly David Cronenberg 1986 4.3
你得到漂亮的打印输出。
答案 1 :(得分:0)
如果我正确理解了您的问题,您希望在列表的每个元素上映射show
并获得一个字符串,其中每个元素都有自己的行。
您可能希望查看来自Data.List的unlines:: [String] -> String
,它完全符合您的要求。
所以,让我们说你从一个更简单的showFilm :: Film -> String
开始,而不是添加尾随的新行:
showAllFilms l = unlines $ map showFilm l