Recursive IO in Haskell

In Haskell, I can easily define a recursive function that takes a value and returns a string:

Prelude> let countdown i = if (i > 0) then (show i) ++ countdown (i-1) else ""
Prelude> countdown 5
"54321"

I want to use the same design to read the available data from a file descriptor. In this particular case, I need to read the data in the same way as hGetContents, but without leaving the handle in a β€œhalf-closed” state, so that I can interact with the stdin / stdout descriptors of the process opened with createProcess:

main = do
    -- do work to get hin / hout handles for subprocess input / output

    hPutStrLn hin "whats up?"

    -- works
    -- putStrLn =<< hGetContents hout

    putStrLn =<< hGetLines hout

    where
        hGetLines h = do
            readable <- hIsReadable h
            if readable
                then hGetLine h ++ hGetLines h
                else []

Gives an error:

Couldn't match expected type `IO b0' with actual type `[a0]'
In the expression: hGetLine h : hGetLines h

I know that there are various libraries available to accomplish what I'm trying to accomplish, but I understand that my question really is how to do recursive I / O. TIA!

+5
3

, O (n)

do-notation, :

import System.IO
import System.IO.Unsafe (unsafeInterleaveIO)

-- Too strict!
hGetLines :: Handle -> IO [String]
hGetLines h = do
    readable <- hIsReadable h
    if readable
        then do
            x  <- hGetLine h
            xs <- hGetLines h
            return (x:xs)
        else return []

, hGetLines !

Lazy,

, . - . unsafeInterleaveIO,

-- Just right
hGetLines' :: Handle -> IO [String]
hGetLines' h = unsafeInterleaveIO $ do
    readable <- hIsReadable h
    if readable
        then do
            x  <- hGetLine h
            xs <- hGetLines' h
            return (x:xs)
        else return []

:

*Main> hGetLines' stdin
123
["123"345
,"345"321
,"321"^D^CInterrupted.
+10

(++) ghci, :

Prelude> :t (++)
(++) :: [a] -> [a] -> [a]

, (, String [Char], ). hGetLine Handle -> IO String, hGetLines IO [String] , . (:) a -> [a] .

if readable
  then do
    -- First you need to extract them
    a <- hGetLine h
    b <- hGetLines h
    -- a and b have type String
    -- Now we can cons them and then go back into IO
    return (a : b)

else []. IO [String]. return []

, putStrLn , (=<< hGetLines h) [String], String, putStrLn. . , . putStrln . concat =<< (hGetLines h). , mapM_ putStrLn (hGetLines h).

+6

, , hGetLines h IO a, [a]. , , if:

if readable
    then return hGetLine h ++ hGetLines h
    else return []
-1

All Articles