将文件读入类型 - Haskell [英] Reading file into types - 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 anInt
to cooperate with your definition ofFilm
? - How do you skip blank or empty lines?
- How do you make
readFilms
accumulate and return a list ofFilm
data?
这篇关于将文件读入类型 - Haskell的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!