3

Haskellでプログラミングをしようとしています。ファイルを読み取ってから、 line 関数を使用してファイル内のすべての行をリストに入れようとしています。部分的なコードは次のとおりです。

file = "muh.rtr"
readTrack :: String -> Track
readTrack file =
    do      let defFile = readFile file
            let fileLines = lines defFile

ただし、次のエラーが発生し続けます。

Parser.hs:22:39:
    Couldn't match expected type `String' with actual type `IO String'
    In the first argument of `lines', namely `defFile'
    In the expression: lines defFile
    In an equation for `fileLines': fileLines = lines defFile

どこかで答えを見つけたいと思って何時間もインターネットを検索してきましたが、今のところそれほど幸運ではありません.

4

5 に答える 5

9

おそらく、次のようなものが必要でした:

readTrack :: String -> IO Track
readTrack file = do defFile <- readFile file
                    let fileLines =  lines defFile
                    -- etc....

...または次のようなもの:

readTrack :: String -> IO Track
readTrack file = do fileLines <- liftM lines (readFile file)
                    -- etc....

しかし、あなたが本当にすべきことは、立ち止まってLearn You a Haskellなどの言語の紹介を見つけて、時間をかけて読むことです。

非常に単純なエラーだけで構成されたコードを GHC にフィードしてから、スタック オーバーフローにエラー メッセージを投稿することは、学習する良い方法ではありません。

于 2012-09-25T20:18:07.833 に答える
6

のタイプreadFile

readFile :: FilePath -> IO String 

<-そのため、結果をバインドするために使用する必要があり、関数は を返す必要がありますIO Track

readTrack :: String -> IO Track
readTrack file =
  do defFile <- readFile file
     let fileLines = lines defFile
     ...

Haskell の IO に関する優れたチュートリアルを読むことをお勧めします。たとえば、Learn You a Haskell for Great Good! の入力と出力の章です。.

于 2012-09-25T20:17:55.587 に答える
5

readFile を返しますIO string。つまり、文字列を返す IO 計算です。これは、返される文字列を「取得」する<-代わりに使用する必要があることを意味します。let

 readTrack file =
    do
        defFile <- readFile file
        ...

let通常の文字列である行の戻り値など、IO 計算ではないものをバインドするために使用できます。

readTrack file =
    do
        defFile <- readFile file
        let fileLines = lines defFile
        ...

最後に、次のようなものを試してみたい値を返す必要があります

readTrack file =
    do
        defFile <- readFile file
        let fileLines = lines defFile
        fileLines --Doesn't actually work!

しかし残念なことに、私たちは "do" ブロックの中にいて、モナド計算を返そうとしているので、 fileLines を io モナドに送り返す必要があります (out 関数はIO [String]ではなくString!を返すことに注意してください)。

readTrack file =
    do
        defFile <- readFile file
        let fileLines = lines defFile
        return fileLines

ここでの「return」は、ほとんどの言語で通常見られるような return ステートメントではないことに注意してください。純粋な関数では使用しないでください。

これはすべて、最初はたくさんのように思えるかもしれません。言語に慣れるまで、純粋な関数 (入力と出力/モナドなし) に固執することをお勧めします。

于 2012-09-25T20:18:23.760 に答える
4

そんなことはできません -- IO モナドに出くわしました。あなたがする必要があるのは次のようなものです:

readTrack :: String -> IO Track
readTrack file = do
   defFile <- readFile file
   let fileLines = lines deffile
   ...
   return whatever

IO T値は、戻り値の型を持つ (式ではなく) ステートメントと考えてくださいT。ステートメントには副作用がありますが、式には副作用がないため、ステートメントを式に変換することはできません。型システムがこれを強制するため、型シグネチャが機能しません。

doブロック内の代入に似た構文が異なることに注意してください。この例では、foo <- barIO操作に使用され、let baz = quux構文は純粋に関数の評価に使用されます。これは、モナド I/O を使用することによる影響です。Haskell の多相型システムの完全な一般性においては、より理にかなっていますが、純粋な操作と副作用のある操作の構文インジケータを持つことも、必ずしも悪いことではありません。

一般に、実装のほとんどを純粋関数領域にとどめておくことをお勧めします: 通常の関数メソッドを使用して純粋計算を実装し、モナドで I/O 操作を記述しますIOリスト内包表記や再帰関数としてより適切なループを IO モナドに書くのは、よくある初心者の間違いです。

于 2012-09-25T20:24:03.823 に答える
3

関数の type が想定されているreadTrack :: String -> Track場合、文字列がファイル名であると確信していますか? おそらくそれはデータです - もしそうなら、使用しないでくださいreadFile。いくつかのサンプルデータを書き、それを使用してテストします。

sampleData = "2 3\n1 30 234 45\n1 2 32 4\n5 3 4 23"

(この宿題に関する SO の他の質問は、ファイル IO を使用しませんでした。あなたは危機に瀕しており、コピーしたくなるかもしれないので、リンクしません。いずれにせよ、Haskell の学習を拒否する場合は、少なくとも私はStackOverflow の検索スキルを向上させる必要があります! :) )

いずれにせよ、IO の問題を解くよりも String の問題を解いた方が、より多くの点数を獲得できると思います。

純粋なバージョンが機能するようになるまで readFile の問題を遅らせてください。そうしないと、必要以上に複雑な IO モナドにほとんどのコードを記述してしまう可能性があります。

あなたが純粋な関数を持っているならreadTrack :: String -> Track、あなたはすることができます

readTrackFrom :: FilePath -> IO Track
readTrackFrom filename = fmap readTrack (readFile filename)

さて、fmap :: Functor f => (a -> b) -> f a -> f bは、純粋な関数を取り、それらを持ち上げて、IO のような別の計算コンテキストで動作するようにします。

IOFunctor(今夜ではなく、明日調べてください) であるため、 type として使用しています(String -> Track) -> IO String -> IO TrackreadTrack :: String -> Track(readFile filename) :: IO String. _

必要に応じて、>>= printまたは適切と思われる方法で行うことができ>>= writeFile newfilenameます。

deriving Show使用後に追加することを忘れないでください。ただし、使用data Track =...している場合は必要ありませんtype Track = ....

于 2012-09-25T21:41:56.790 に答える