将文件读入类型 - Haskell [英] Reading file into types - Haskell
问题描述
type Rating =(String,Int)
类型Film =(String,String,Int,[Rating])
我有一个文件数据:
Blade Runner
Ridley Scott
1982
( Amy,5),(Bill),8),(Ian,7),(Kevin,9),(Emma,4),(Sam,7), ,4)
The Fly
David Cronenberg
1986
(Megan,4),(Fred,7), Chris,5),(Ian,0),(Amy,6)
我怎样才能通过文件存储所有的条目到像FilmDatabase = [电影]?
Haskell提供了一个绘制您的方法的独特方式。以你知道的开始
模块Main其中
类型Rating =(String,Int)
type Film =(String,String,Int,[Rating])
main :: IO()
main = do
films< - readFilmsratings.dat
print films
试图将这个程序加载到ghci中会产生
films.hs:8:12:不在范围内:`readFilms'
它需要知道什么 readFilms
是,所以添加足够的代码来继续移动。
readFilms = undefined
这是一个函数,它应该执行与 Film
数据。重新加载此代码(使用:reload
命令或简称:r
)以获得
films.hs:9:3:
约束中含糊不清的类型变量`a0':使用`print'引起的
(显示a0)
...
Prelude>:t print
print ::显示a => a - > IO()
换句话说, print
接受一个参数,非正式地知道如何显示自身(即将其内容转换为字符串)并创建一个I / O操作当执行时输出该字符串。它几乎或多或少是你期望 print
的工作方式:
Prelude> print 3
3
Prelude> printhi
hi
我们知道我们要 print >
文件中的数据,但是,虽然很好,但ghc不能理解我们的想法。但是在添加一个类型提示之后
readFilms :: FilePath - >电影
readFilms =未定义
我们收到一个新错误。 b
films.hs:8:12:
无法与实际类型'(String,String,Int,[Rating]匹配预期类型'IO t0'
])'
预期类型:IO t0
实际类型:电影
在`readFilms'调用的返回类型中
在'do'表达式中:影片< - readFilmsratings.dat
该错误告诉您编译器对您的故事感到困惑。你说 readFilms
应该给它一个 Film
,但是你在 main
,计算机必须首先执行一些I / O然后然后返回 Film
数据。
在Haskell中,这是纯字符串(比如JamieB
)和a在你提示你输入Stack Overflow用户名后,从键盘读取输入。
现在我们知道我们可以绘制 readFilms
as
readFilms :: FilePath - > IO Film
readFilms = undefined
以及代码编译! (但我们还不能运行它。)
要挖掘另一个图层,假设单个电影的名称是 ratings.dat
,然后在其他地方放置占位符来保持类型检查器的快乐。
readFilms :: FilePath - > IO Film
readFilms path = do
alldata< - readFile path
return(alldata,,0,[])
这个版本可以编译,甚至可以在ghci提示符处输入 main
来运行它。
在 dave4420的答案中提供了有关其他功能的重要提示。把上面的方法想象成一个拼图游戏,其中单个棋子是功能。为了您的程序正确,所有类型必须合在一起。你可以通过采取上述的小补充措施来使你的最终工作计划取得进展,如果你的草图中有错误,类型分析工具会告诉你。
物联网out:
- 如何将整个输入块转换为单独的行
- 你找出你的程序正在检查的行是标题,导演等?
- 你如何转换文件中的年份(a
String )添加到
Int
以配合您的定义电影
? - 你如何跳过空行或空行?
电影
数据 Right now I have two types:
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)
How can I look through then file storing all of the entries into something like FilmDatabase = [Film] ?
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
Attempting to load this program into ghci will produce
films.hs:8:12: Not in scope: `readFilms'
It needs to know what readFilms
is, so add just enough code to keep moving.
readFilms = undefined
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' ...
The type of print
is
Prelude> :t print print :: Show a => a -> IO ()
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"
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
we get a new error.
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"
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.
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.
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.)
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, [])
This version compiles, and you can even run it by entering main
at the ghci prompt.
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.
Things to figure out:
- 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屋!