あるリストから最初に'x'が現れるまでのリストを取得するには、
h :: [Char] h = takeWhile (/='x') ['a'..]
しますが、これをこのままIOにして、
h' :: IO [Char] h' = takeWhile (/='x') `liftM` mapM (\_ -> getChar) (cycle [1])
とすると、当然ですが、終わらなくなります。
f :: IO [Char] f = reverse `liftM` f' [] where f' p = do c <- getChar if c == 'x' then return p else f' $ c:p
のように自前で再帰するか、再帰部分をunfoldMとして外に出して、
g :: IO [Char] g = unfoldM g' 0 where g' _ = do c <- getChar return $ if c == 'x' then Nothing else Just (c, 0) unfoldM :: Monad m => (b -> m (Maybe (a, b))) -> b -> m [a] unfoldM f x = do v <- f x case v of Just (a, b) -> unfoldM f b >>= return . (a:) Nothing -> return []
のようにすれば良いのですが、もう少しシンプルにできる方法はないものでしょうか。