0

私は Haskell を使用した IO に慣れていないので、何度も読んでいますが、コードはまだ機能しません。

アプリでやりたいこと:

  1. ファイル (file1.txt、file2.txt、...) のすべての行を読み取ります。すべての行には各行に数字が含まれています (1.12345 のような浮動小数点数)。
  2. これらすべての行を並べ替えます (文字列の並べ替えまたはフロートの並べ替えは関係ありません。文字列の並べ替えの方が速いと思いますか?)
  3. リストの中央の要素を取得して出力します

これは私がこれまでに持っているコードです。[String] を渡すときに、関数「middle」が正常に機能することを保証できます。

middle :: [a] -> a
middle xs = (drop ((l - 1) `div ` 2) xs) !! 0
            where l = length xs

getSortedMiddleElement :: Int -> String
getSortedMiddleElement i = do
    dat <- readFile $ "file" ++ (show i) ++ ".txt"
    return $ middle $ sort $ lines dat

「Int -> Content」関数 (私は Yesod を使用) から getSortedMiddleElement を呼び出しています。この関数では、番号が URL 経由で渡され、中間要素がユーザーに返されます。文字列からコンテンツを取得するには、「IO文字列」ではなく「文字列」である必要があります...どうすれば簡単に実現できますか?

前もって感謝します!

4

1 に答える 1

5

型シグネチャは、関数が純粋であることを示しています (つまり、Int を取り、String を返します) が、内部では IO を実行しています! Haskell では、そのような関数を作成することはできません。ファイルから読み取ったものはすべて IO モナドに永久にスタックされます。それで終わりです (もちろん、安全でない関数は除きます)。

この場合、Yesod は非常に IO ベースのフレームワークであるため、それほど悪くはありません。すべてのネットワーク トラフィックも IO モナドでスタックします。

モナド変換子スタックにいる場合、スタックの各レベルでモナド計算にアクセスできますが、直接アクセスできるのはそのうちの 1 つだけです。lift計算をモナドからスタック内の 1 層下の変換されたモナドに移動するために使用します。がスタック内にある場合IOは、下のレイヤーがいくつあっても、 を介してそのアクションに直接アクセスできますliftIO

したがって、持っているtype T = ReaderT String IO場合は、機能がある可能性がありますfoo :: Int -> T String。この関数では、モナド機能でモナドTを変換するIOモナドで操作しReaderます。このコンテキストでは、結果lift readFileを得る代わりに、IO String結果を得ることができますT String。ただし、これは単にIO Stringラップされた型なので、モナドReaderTをエスケープするようなトリッキーなことをしたとは思わないでください。IO少しわかりにくいかもしれないので、例を見てみましょう。

import Control.Monad.Reader (ReaderT)
import Control.Monad.Writer (WriterT)
import Control.Monad.Trans  (lift, liftIO)

type T = ReaderT String IO
getSortedMiddleElement :: Int -> IO String

foo :: Int -> T String
foo n = do
  str <- lift $ getSortedMiddleElement n --str holds a pure String now
  lift $ putStrLn str                    --get `putStrLn` from IO and pass the String
  return str                             --let's wrap it back in T now

しかし、IO から 1 層以上離れている場合はどうなるでしょうか。試してみましょう:

type W = WriterT String T -- WriterT String (ReaderT String IO)

-- This doesn't work; lift only gives you access to the next layer's actions
-- but IO is now more than one layer away!
--
--bar n = do
--  str <- lift $ getSortedMiddleElement n

-- Instead, we need liftIO, which will access IO across many transformer layers
bar :: Int -> W String
bar n = do
  str <- liftIO $ getSortedMiddleElement n
  liftIO $ putStrLn str
  return str
于 2013-08-26T01:49:21.983 に答える