-2

現在、私には2つのタイプがあります。

type Rating = (String, Int)

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

このデータを含むファイルがあります:

"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]のようなファイルに保存しているファイルを確認するにはどうすればよいですか?

4

3 に答える 3

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

このプログラムを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ですか?
于 2012-04-16T17:14:05.617 に答える
6

これは宿題ですか?

これらの関数が役立つ場合があります。

Stringそれはと同じであることを忘れないでください[Char]

いくつかの手がかり:

  • dropWhile nullリストの先頭から空の行を削除します
  • break nullリストを空でない行の先頭の実行とリストの残りの部分に分割します
于 2012-04-16T13:53:00.970 に答える
0

Haskellには、型を使用して適切な関数を見つけるための優れた方法があります。例:Gregsの回答では、彼はあなたに(とりわけ)映画の年を文字列から整数に変換する方法を理解してほしいと思っています。さて、あなたは関数が必要です。その関数のタイプはどうあるべきですか?文字列を受け取り、Intを返すため、型は。である必要がありますString -> Int。それができたら、Hoogleに移動してそのタイプを入力します。これにより、類似したタイプの関数のリストが表示されます。必要な関数のタイプは実際には少し異なりますRead a => String -> a---リストの少し下にありますが、タイプを推測して結果のリストをスキャンすることは、多くの場合、非常に便利な戦略です。

于 2012-04-16T21:18:45.120 に答える