6

Haskell で遅延 IO を把握するための旅で、次のことを試しました。

main = do
  chars <- getContents
  consume chars

consume :: [Char] -> IO ()
consume [] = return ()
consume ('x':_) = consume []
consume (c : rest) = do
  putChar c
  consume rest

「x」を押すまで、標準入力に入力されたすべての文字をエコーするだけです。

したがって、次の行に沿って何かを行うことgetContentsを使用して再実装できるはずだと素朴に考えました。getChar

myGetContents :: IO [Char]
myGetContents = do
  c <- getChar
  -- And now?
  return (c: ???) 

IO モナドの概念全体を壊してしまう???タイプの関数が必要になるため、それほど単純ではないことがわかりました。IO [Char] -> [Char]

getContents(というよりは)の実装をチェックするとhGetContents、汚い IO のソーセージ ファクトリ全体が明らかになります。myGetContentsダーティなコード、つまりモナドを壊すコードを使わないと実装できない私の仮定は正しい ですか?

4

3 に答える 3

6

unsafeInterleaveIO :: IO a -> IO aそのアクションの結果が評価されるまで、その引数アクションの実行を遅らせる新しいプリミティブが必要です。それで

myGetContents :: IO [Char]
myGetContents = do
  c <- getChar
  rest <- unsafeInterleaveIO myGetContents
  return (c : rest)
于 2016-12-03T18:16:28.620 に答える
1

可能な限り、何も使用しないでくださいSystem.IO.Unsafe。これらは参照透過性を無効にする傾向があり、どうしても必要な場合を除き、Haskell で使用される一般的な関数ではありません。

型シグネチャを少し変更すると、問題に対してより慣用的なアプローチができると思います。

consume :: Char -> Bool
consume 'x' = False
consume _   = True

main :: IO ()
main = loop
  where
    loop = do
      c <- getChar
      if consume c
      then do
        putChar c
        loop
      else return ()
于 2016-12-04T00:20:30.990 に答える