将文件读入类型 - Haskell

Jam*_*ieB -1 haskell file input

现在我有两种类型:

type Rating = (String, Int)

type Film = (String, String, Int, [Rating])
Run Code Online (Sandbox Code Playgroud)

我有一个包含此数据的文件:

"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)
Run Code Online (Sandbox Code Playgroud)

我怎样才能查看将所有条目存储到FilmDatabase = [Film]之类的文件?

Gre*_*con 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
Run Code Online (Sandbox Code Playgroud)

试图将这个程序加载到ghci中会产生

films.hs:8:12: Not in scope: `readFilms'

它需要知道是什么readFilms,所以添加足够的代码来继续前进.

readFilms = undefined
Run Code Online (Sandbox Code Playgroud)

这是一个应该做与Film数据相关的功能.获取此代码(使用:reload命令或:r简称)

films.hs:9:3:
    Ambiguous type variable `a0' in the constraint:
      (Show a0) arising from the use of `print'
    ...

类型print

Prelude> :t print
print :: Show a => a -> IO ()

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

Prelude> print 3
3
Prelude> print "hi"
"hi"

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

readFilms :: FilePath -> Film
readFilms = undefined
Run Code Online (Sandbox Code Playgroud)

我们得到一个新的错误.

films.hs:8:12:
    Couldn't match expected type `IO t0'
                with actual type `(String, String, Int, [Rating])'
    Expected type: IO t0
      Actual type: Film
    In the return type of a call of `readFilms'
    In a stmt of a 'do' expression: films <- readFilms "ratings.dat"

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

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

所以现在我们知道我们可以草绘readFilms

readFilms :: FilePath -> IO Film
readFilms = undefined
Run Code Online (Sandbox Code Playgroud)

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

要挖掘另一层,假装单个电影的名称是唯一的数据,ratings.dat并在其他地方放置占位符,以保持typechecker的快乐.

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

此版本编译,您甚至可以通过输入mainghci提示符来运行它.

dave4420中,答案是关于其他功能使用的很好的提示.可以把上面的方法想象成拼凑拼图,其中各个部分都是功能.为了使您的程序正确,所有类型必须放在一起.如上所述,您可以通过采取小的babysteps来向最终的工作程序取得进展,如果您的草图中有错误,typechecker会通知您.

需要弄清楚的事情:

  • 如何将整个输入的blob转换为单独的行?
  • 你如何判断你的程序正在检查的行是标题,导演等等?
  • 如何将文件(a String)中的年份转换为Int与您的定义合作Film
  • 你如何跳过空白或空行?
  • 如何readFilms累积并返回Film数据列表?


dav*_*420 6

这是家庭作业吗?

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

请记住,这String是一样的[Char].

一些线索:

  • dropWhile null 将从列表的开头摆脱空行
  • break null 将列表拆分为非空行的前导,以及列表的其余部分