使用纯非I / O Haskell函数在新行上拆分列表

时间:2014-03-06 14:30:30

标签: haskell

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的新手,任何帮助都会受到赞赏。

2 个答案:

答案 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.Listunlines:: [String] -> String,它完全符合您的要求。 所以,让我们说你从一个更简单的showFilm :: Film -> String开始,而不是添加尾随的新行:

showAllFilms l = unlines $ map showFilm l