-2

现在我有两种类型:

type Rating = (String, Int)

type Film = (String, String, Int, [Rating])

我有一个文件,其中包含以下数据:

"Blade Runner"
"Ridley Scott"
1982
("Amy",5), ("Bill",8), ("Ian",7), ("Kevin",9), ("Emma",4), ("Sam",7), ("Megan",4)

"The Fly"
"David Cronenberg"
1986
("Megan",4), ("Fred",7), ("Chris",5), ("Ian",0), ("Amy",6)

我如何查看将所有条目存储到类似 FilmDatabase = [Film] 的文件?

4

3 回答 3

7

Haskell 提供了一种独特的方式来勾勒出你的方法。从你知道的开始

module Main where

type Rating = (String, Int)
type Film = (String, String, Int, [Rating])

main :: IO ()
main = do
  films <- readFilms "ratings.dat"
  print films

尝试将此程序加载到 ghci 将产生

films.hs:8:12:不在范围内:`readFilms'

它需要知道是什么readFilms,所以添加足够的代码以继续移动。

readFilms = undefined

它是一个应该做与Film数据相关的事情的函数。重新加载此代码(使用:reload命令或:r简称)以获取

电影.hs:9:3:
    约束中的模糊类型变量“a0”:
      (Show a0) 使用 `print' 引起的
    ...

的类型print

前奏> :t 打印
打印::显示a => a -> IO ()

换句话说,print接受一个参数,该参数非正式地知道如何显示自己(即,将其内容转换为字符串)并创建一个 I/O 操作,该操作在执行时输出该字符串。这或多或少是您期望print的工作方式:

前奏>打印3
3
前奏>打印“嗨”
“你好”

我们知道我们想要从文件中print获取Film数据,但是,虽然很好,但 ghc 无法读懂我们的想法。但是在添加了类型提示之后

readFilms :: FilePath -> Film
readFilms = undefined

我们得到一个新的错误。

电影.hs:8:12:
    无法匹配预期类型“IO t0”
                具有实际类型 `(String, String, Int, [Rating])'
    预期类型:IO t0
      实际类型:电影
    在“readFilms”调用的返回类型中
    在“do”表达式中:电影 <- readFilms "ratings.dat"

该错误告诉您编译器对您的故事感到困惑。你说readFilms应该给它一个Film,但是你调用它的方式main,计算机应该首先执行一些 I/O,然后返回Film数据。

在 Haskell 中,这是字符串(比如"JamieB")和副作用(比如在提示您输入 Stack Overflow 用户名后从键盘读取输入)之间的区别。

所以现在我们知道我们可以画readFilms

readFilms :: FilePath -> IO Film
readFilms = undefined

并且代码编译!(但我们还不能运行它。)

要深入挖掘另一层,假设单个电影的名称是其中唯一的数据,ratings.dat并在其他任何地方放置占位符以保持类型检查器满意。

readFilms :: FilePath -> IO Film
readFilms path = do
  alldata <- readFile path
  return (alldata, "", 0, [])

这个版本可以编译,你甚至可以通过main在 ghci 提示符下输入来运行它。

dave4420 的回答中,有关于其他要使用的功能的很好的提示。把上面的方法想象成一个拼图游戏,其中各个部分都是函数。为了使您的程序正确,所有类型都必须组合在一起。您可以通过采取上述小步骤来朝着最终的工作程序取得进展,如果您的草图中有错误,类型检查器会通知您。

要弄清楚的事情:

  • 如何将整个输入块转换为单独的行?
  • 您如何确定您的程序正在检查的行是否是头衔、导演等?
  • 您如何将文件 (a String) 中的年份转换为 anInt以配合您的定义Film
  • 你如何跳过空白或空行?
  • 你如何使readFilms累积并返回Film数据列表?
于 2012-04-16T17:14:05.617 回答
6

这是作业吗?

您可能会发现这些功能很有用:

请记住,String与 相同[Char]

一些线索:

  • dropWhile null将摆脱列表开头的空行
  • break null将列表拆分为非空行的前导运行,以及列表的其余部分
于 2012-04-16T13:53:00.970 回答
0

Haskell 有一种很好的方法来使用类型来找到正确的函数。例如:在 Gregs 的回答中,他希望您弄清楚(除其他外)如何将电影的年份从 String 转换为 Int。好吧,你需要一个函数。该函数的类型应该是什么?它接受一个字符串并返回一个 Int,所以类型应该是String -> Int. 一旦你有了它,去Hoogle并输入那个类型。这将为您提供具有相似类型的函数列表。你需要的函数实际上有一个稍微不同的类型——Read a => String -> a所以它在列表的下方,但猜测一个类型然后扫描结果列表通常是一个非常有用的策略。

于 2012-04-16T21:18:45.120 回答