将文件读入类型 - Haskell [英] Reading file into types - Haskell

查看:22
本文介绍了将文件读入类型 - Haskell的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

现在我有两种类型:

type Rating = (String, Int)

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

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

I have a file that has this data in it:

"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] 的文件中?

How can I look through then file storing all of the entries into something like FilmDatabase = [Film] ?

推荐答案

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

Haskell provides a unique way of sketching out your approach. Begin with what you know

module Main where

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

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

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

Attempting to load this program into ghci will produce

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

它需要知道 readFilms 是什么,所以添加足够的代码以保持移动.

It needs to know what readFilms is, so add just enough code to keep moving.

readFilms = undefined

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

It is a function that should do something related to Film data. Reload this code (with the :reload command or :r for short) to get

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 的工作方式:

In other words, print takes a single argument that, informally, knows how to show itself (that is, convert its contents to a string) and creates an I/O action that when executed outputs that string. It’s more-or-less how you expect print to work:

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

我们知道我们想从文件中打印Film 数据,但是,虽然很好,ghc 无法读懂我们的想法.但是添加类型提示后

We know that we want to print the Film data from the file, but, although good, ghc can’t read our minds. But after adding a type hint

readFilms :: FilePath -> Film
readFilms = undefined

我们收到一个新错误.

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 和 then 返回 Film 数据.

The error tells you that the compiler is confused about your story. You said readFilms should give it back a Film, but the way you called it in main, the computer should have to first perform some I/O and then give back Film data.

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

In Haskell, this is the difference between a pure string, say "JamieB", and a side effect, say reading your input from the keyboard after prompting you to input your Stack Overflow username.

所以现在我们知道我们可以将 readFilms 草图为

So now we know we can sketch readFilms as

readFilms :: FilePath -> IO Film
readFilms = undefined

然后代码就编译好了!(但我们还不能运行它.)

and the code compiles! (But we can’t yet run it.)

要深入研究另一层,假设ratings.dat 中只有一部电影的名称,并在其他地方放置占位符以使类型检查器满意.

To dig down another layer, pretend that the name of a single movie is the only data in ratings.dat and put placeholders everywhere else to keep the typechecker happy.

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

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

This version compiles, and you can even run it by entering main at the ghci prompt.

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

In dave4420’s answer are great hints about other functions to use. Think of the method above as putting together a jigsaw puzzle where the individual pieces are functions. For your program to be correct, all the types must fit together. You can make progress toward your final working program by taking little babysteps as above, and the typechecker will let you know if you have a mistake in your sketch.

需要解决的问题:

  • 如何将整个输入块转换为单行?
  • 您如何确定您的程序正在检查的行是否是标题、导演等?
  • 您如何将文件中的年份(String)转换为 Int 以配合您对 Film 的定义?
  • 如何跳过空白行或空行?
  • 如何让 readFilms 累积并返回 Film 数据列表?
  • How do you convert the whole blob of input to individual lines?
  • How do you figure out whether the line your program is examining is a title, a director, and so on?
  • How do you convert the year in your file (a String) to an Int to cooperate with your definition of Film?
  • How do you skip blank or empty lines?
  • How do you make readFilms accumulate and return a list of Film data?

这篇关于将文件读入类型 - Haskell的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆