2012-04-16 11 views
-1

は、今私は2つのタイプがあります。読書ファイルHaskellの

"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) 

は、私が目を通すことができますどのようにして、すべてのファイル保存:

type Rating = (String, Int) 

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

私はそれでこのデータを持つファイルを持っていますFilmDatabase = [Film]のようなものにエントリの?

+0

のような単純なもの: \t \t \t \t名< - getlineの \t \t \t \t内容< - readFileの名 :displayFile :: IO() displayFileは= \t \t \t \t putStrLnは、 "ファイル名を入力します" ん\t \t \t putStrLnの内容 – JamieB

+0

どのビットで問題がありますか? – dave4420

+0

私はどのように行をフィルタリングし、右のタイプに追加するのか分かりません。各エントリの最初の行は文字列でなければならず、映画(タイトルなど)のタイトルに追加する必要がありますC#ではシンプルですが、私はそれをHaskellで信じられないほど難しくしています。 – JamieB

答えて

7

ハスケルは、あなたのアプローチをスケッチするユニークな方法を提供します。あなたはGHCiのにこのプログラムをロードしようとすると、

module Main where 

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

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

知っていることで始まると、それはreadFilmsが何であるかを知っているので、移動保つために必要なだけのコードを追加する必要が

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

を生成します。

readFilms = undefined 

これは、Filmデータに関するものです。 printは、非公式に、どのように知っている単一の引数を取り、printの種類は、言い換えれば

Prelude> :t print 
print :: Show a => a -> IO()

ある

films.hs:9:3: 
    Ambiguous type variable `a0' in the constraint: 
     (Show a0) arising from the use of `print' 
    ...

を取得する(:reloadコマンドまたは略して:rで)このコードをリロードその内容を文字列に変換し、実行時にその文字列を出力するI/Oアクションを作成します。それ’ S多かれ少なかれあなたはprintが動作することを期待する方法:

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

私たちは、ファイルからFilmデータをprintしたいことを知っている、しかし、良いものの、GHCはtは私たちの心を読む’ことができます。しかし、タイプヒントを追加した後

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"

このエラーは、コンパイラがあなたの話について混乱していることを示しています。あなたはreadFilmsFilmを返すべきだと言いましたが、mainでそれを呼び出す方法では、コンピュータは最初にいくつかのI/Oを実行し、を実行してからデータを返す必要があります。Film Haskellで

、これは純粋文字列、"JamieB"を言うと、副作用との間の差である、入力にあなたのスタックオーバーフローのユーザー名をあなたに要求した後、キーボードからの入力内容を読ん言います。

だから今、私たちはreadFilms

readFilms :: FilePath -> IO Film 
readFilms = undefined 

としてをスケッチし、コードのコンパイルすることができます知っています!

別のレイヤーを掘り下げるには、1つのムービーの名前がratings.datの唯一のデータであり、タイプチェッカーを幸せにするために他の場所に置くことをお勧めします。

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

このバージョンでは、コンパイルし、あなたもGHCiのプロンプトでmainを入力することによって、それを実行することができます。

dave4420’s answerは、使用する他の機能についての大きなヒントです。上記の方法は、個々の要素が機能するジグソーパズルを組み立てることと考えてください。あなたのプログラムが正しいようにするには、すべてのタイプが一緒に適合しなければなりません。あなたは上記のようにほとんどbabystepsを取ることによってあなたの最終作業プログラムに向かって進歩することができ、あなたがあなたのスケッチに間違いがあるかどうかをタイプチェッカーが知らせます。把握する

もの:

  • あなたは個々の行への入力の全体のブロブを変換する方法を教えてください。
  • あなたのプログラムが調査している行がタイトルかディレクターかなどをどのように把握していますか?
  • ファイルの年(String)をIntに変換すると、Filmの定義にどのように協力しますか?
  • 空白行または空白行をどのようにスキップしますか?
  • readFilmsをどのように蓄積し、Filmのデータのリストを返しますか?
6

この宿題はありますか?

あなたは、これらの機能は便利かもしれません:

String[Char]と同じです。

いくつかの手がかり:

  • dropWhile nullは、リストの先頭
  • break nullから空行を取り除くだろうが、非空行の主要な実行、およびリストの残りの部分にリストを分割します
0

ハスケルは、適切な関数を見つけるために型を使用する素晴らしい方法があります。たとえば、Gregsの答えでは、映画の年をStringからIntに変換する方法を(他のものの中でも)把握したいと考えています。さて、関数が必要です。その機能の種類は何でしょうか?それは文字列を取り、Intを返すので、型はString -> Intでなければなりません。いったんこれを取得したら、Hoogleに行き、そのタイプを入力します。これにより、同様のタイプの関数のリストが得られます。あなたが実際に必要とする機能は、実際にはわずかに異なるタイプ - Read a => String -> a - ですので、リストのビットダウンですが、タイプを推測して結果リストをスキャンすることは、しばしば非常に便利な方法です。