Лень в Haskell - как заставить IO происходить раньше?

Я только начал изучать Haskell. Ниже приведен код, написанный в императивном стиле, который реализует простой сервер - он распечатывает заголовки HTTP-запроса. Помимо того факта, что мне нужно переосмыслить его в Haskell, чтобы работать с ленивыми списками и функциями более высокого порядка, я хотел бы четко понять, почему он не делает то, что я планировал. Он всегда один позади - я нажимаю на него запрос, ничего не происходит, нажимаю снова, он печатает первый запрос, нажимает его в третий раз, он печатает второй запрос и т. Д. Это почему? И какое минимальное изменение в этом коде привело бы к тому, что он печатал сразу, когда поступил запрос?

import Network
import System.IO
import Network.HTTP.Headers

acceptLoop :: Socket -> IO ()
acceptLoop s = do
  (handle, hostname, _) <- accept s
  putStrLn ("Accepted connection from " ++ hostname)
  text <- hGetContents handle
  let lns = lines text
      hds = tail lns
  print $ parseHeaders hds
  hClose handle
  acceptLoop s


main :: IO ()
main = do
  s <- listenOn (PortNumber 8080)
  acceptLoop s

спасибо, Роб

Продолжение

Все ответы были полезными. Приведенный ниже код работает, но пока не использует строки байтов, как было предложено. Последующий вопрос: можно ли заменить ioTakeWhile некоторыми функциями из стандартных библиотек, возможно, в Control.Monad?

ioTakeWhile :: (a -> Bool) -> [IO a] -> IO [a]
ioTakeWhile pred actions = do
  x <- head actions
  if pred x
    then (ioTakeWhile pred (tail actions)) >>= \xs -> return (x:xs)
    else return []

acceptLoop :: Socket -> IO ()
acceptLoop s = do
  (handle, hostname, _) <- accept s
  putStrLn ("Accepted connection from " ++ hostname)
  let lineActions = repeat (hGetLine handle)
  lines <- ioTakeWhile (/= "\r") lineActions
  print lines
  hClose handle
14
задан Don Stewart 24 April 2011 в 16:30
поделиться