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略して)リロードして、
Films.hs:9:3:
制約内のあいまいな型変数`a0':
(a0を表示)`print'の使用から生じる
..。
タイプprintは
プレリュード>:t print
print :: Show a => a-> IO()
言い換えるprintと、非公式に、それ自体を表示する方法(つまり、その内容を文字列に変換する方法)を知っている単一の引数を取り、実行時にその文字列を出力するI/Oアクションを作成します。それは多かれ少なかれあなたがprint働くことを期待する方法です:
プレリュード>プリント3
3
プレリュード>「こんにちは」を印刷
"こんにちは"
printファイルからデータを取得したいことはわかってFilmいますが、ghcは私たちの心を読み取ることができません。しかし、タイプヒントを追加した後
readFilms :: FilePath -> Film
readFilms = undefined
新しいエラーが発生します。
Films.hs:8:12:
期待されるタイプ`IOt0'と一致しませんでした
実際の型は`(String、String、Int、[Rating]) '
予想されるタイプ:IO t0
実際のタイプ:フィルム
`readFilms'の呼び出しのリターンタイプ
'do'式のstmt:films <-readFilms "ratings.dat"
このエラーは、コンパイラがストーリーについて混乱していることを示しています。あなたはreadFilmsそれを返す必要があると言いましたFilmが、あなたがそれを呼んだようにmain、コンピュータは最初にいくつかのI / Oを実行し、次にデータを返す必要がありFilmます。
Haskellでは、これは純粋な文字列、たとえば"JamieB"、と副作用、たとえばStackOverflowのユーザー名の入力を求められた後にキーボードから入力を読み取ることの違いです。
これで、次のようにスケッチできることがわかり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の答えには、使用する他の関数に関する優れたヒントがあります。上記の方法は、個々のピースが機能するジグソーパズルを組み立てる方法と考えてください。プログラムを正しくするには、すべてのタイプが一致している必要があります。上記のように少し手を加えることで、最終的な作業プログラムに進むことができます。タイプチェッカーは、スケッチに誤りがあるかどうかを通知します。
理解すべきこと:
- 入力のブロブ全体を個々の行にどのように変換しますか?
- あなたのプログラムが調べているラインがタイトル、ディレクターなどであるかどうかをどのように判断しますか?
Stringファイル(a )の年を、Intの定義に協力するためにどのように変換しますFilmか?
- 空白行または空行をスキップするにはどうすればよいですか?
- データのリストをどのように
readFilms蓄積して返すのFilmですか?