CPS

Aug 21, 2009 23:35


По мотивам поста
mr_aleph( reinventing CPS - functional pearl from my own soul) решил попробовать написать это на Haskell, если я, конечно, правильно понял задание :)

Для начала определим два типа:
data Continuation r = Continue (IO (Continuation r)) | Fail String | Done r
type Continuable a = forall r . ContT (Continuation r) IO a

Вычисление может либо вернуть ошибку, либо остановиться на «контрольной точке» (например, файл скачан). Соответственно если дальнейшие действия провалятся, вычисление продолжит работу с этой контрольной точки. Done здесь нужен для возврата окончательного значения.

Теперь две функции, одна прекращает вычисление с ошибкой, а вторая соответственно «коммитит» значение и продолжение:
done v = ContT $ \k -> return (Continue (k v))
stop s = ContT $ \_ -> return (Fail s)

Остаётся написать ещё две примитивные функции - одна для оборачивания ContT в наш тип, а вторая для запуска вычисления, они тоже простые:
routine :: ContT (Continuation r) IO r -> IO (Continuation r)
routine m = runContT m (return . Done)
type ContinuationState r = Either r (String, IO (Continuation r))
run :: IO (Continuation r) -> IO (ContinuationState r)
run k = do
  k' <- k
  case k' of
    (Done v) -> return $ Left v
    (Fail s) -> return $ Right (s, k)
    (Continue k) -> run k

Ну и последнее, перезапуск вычисления. По сути тот же run, но принимающий промежуточный результат:
retry :: (String -> IO ()) -> ContinuationState r -> IO (ContinuationState r)
retry _ (Left v) = return $ Left v
retry out (Right (s, k)) = out s >> run k

Тест:
getInput prompt = do
  liftIO $ putStrLn prompt
  s <- liftIO $ getLine
  if null s
    then stop "Empty input"
    else done s

bar = routine $ do
  x <- getInput "Input value 1:"
  y <- getInput "Input value 2:"
  z <- getInput "Input value 3:"
  return (x ++ " - " ++ y ++ " - " ++ z)

Теперь если на второй запрос ввести пустую строку, вычисление остановится, после retry продолжит сразу со второго запроса.
Ну и forkIO туда впихнуть по желанию.

haskell

Previous post Next post
Up