38

テキストのインデックスを作成するために、Haskell で一連のコードを作成しました。トップ関数は次のようになります。

index :: String -> [(String, [Integer])]
index a = [...]

ここで、この関数にファイルから読み取った文字列を渡したいと思います。

index readFile "input.txt"

readFile のタイプが FilePath -> IO String であるため、これは機能しません。

予想される型 'String' を推測された型 'IO String' と一致させることができませんでした

エラーが表示されますが、次のタイプの関数が見つかりません:

IO String -> String

成功の鍵はモナドのどこかにあると思いますが、問題を解決する方法が見つかりませんでした。

4

4 に答える 4

43

readFile アクションを呼び出す関数を簡単に作成し、結果をインデックス関数に渡すことができます。

readAndIndex fileName = do
    text <- readFile fileName
    return $ index text

ただし、IO モナドはそれを使用するすべてのものを汚染するため、この関数の型は次のようになります。

readAndIndex :: FilePath -> IO [(String, [Integer])]
于 2009-11-04T18:13:40.123 に答える
29

そのような機能がないのには十分な理由があります。

Haskell には、機能的純度という概念があります。これは、関数が同じパラメーターで呼び出された場合、常に同じ結果を返すことを意味します。IO が許可される唯一の場所は IO モナドの内部です。

機能が*あった場合

index :: IO String -> String

次に、次のように呼び出すことで、突然どこでもIO アクションを実行できます。

index (launchMissiles >> deleteRoot >> return "PWNd!")

関数の純粋性は、私たちが失いたくない非常に便利な機能です。これにより、コンパイラーは関数をより自由に並べ替えたりインライン化したりできるようになり、セマンティクスを変更せずに異なるコアにスパークさせることができ、プログラマーにも感覚を与えることができます。関数がその型からできることとできないことを知ることができれば、セキュリティの観点からです。

※実はこんな機能がありますそれは呼ばれており、非常に正当な理由unsafePerformIOで呼ばれています。自分が何をしているのか 100% 確信がない限り、使用しないでください。

于 2009-11-04T19:29:24.743 に答える
16

IOのモナド部分を取り除くことはできませんIO String。つまり、関数を return にする必要がありますIO [(String, [Integer])]

モナドについてもっと学ぶことをお勧めしますが、今のところ、次のliftM関数で問題を解決できます。

liftM index (readFile "input.txt")

liftMこの署名があります:

liftM :: Monad m => (a -> b) -> m a -> m b

非モナド関数を取り、それをモナド関数に変換します。

于 2009-11-04T17:31:46.773 に答える
9
fmap index $ readFile "input.txt"

また

readFile "input.txt" >>= return . index

モナドとファンクターを調べたいと思うかもしれません

于 2009-11-05T03:20:55.983 に答える