[Haskell-cafe] Interpreting synchronized streams (pre-IO monad Haskell)

Jiri Jakes jiri at jirijakes.eu
Thu Feb 13 12:10:06 UTC 2020


Before introduction of IO monad, first versions of Haskell used
synchronised streams [1]:

  main :: [Response] -> [Request]
where Response and Request were ADTs containing all possible actions
and responses:

  data Request = ReadFile Name | ... | AppendChan Name String | ...
  data Response = Success | Str String | Bn Bin | Failure ...

I wanted to write an interpreter of this representation using a
simplified version:

  import System.Environment (getArgs)

  data Response = Success | StrList [String]
  data Request = GetArgs | PutStr String

  eval :: Request -> IO Response
  eval GetArgs = StrList <$> getArgs
  eval (PutStr s) = putStrLn s >> return Success

  main' :: [Response] -> [Request]
  main' ~(StrList args : _) =
    [ GetArgs,
      PutStr (show args)

  main :: IO ()
  main = ???

I can imagine how interpreting main' could work, thanks to laziness.
However, when actually trying to implement it, I get lost. I cannot
figure out how could I read requests (result of calling main') before
having something to pass to main'. Having a look at ancient version of
GHC [2] didn't help either.

Is it actually possible without some low-level tricks? Perhaps using
mutually recursive functions? Or by converting to continuations somehow?

Thank you!


[1] http://haskell.org/definition/haskell-report-1.0.ps.gz
[2] https://downloads.haskell.org/~ghc/0.29/ghc-0.29-src.tar.gz

More information about the Haskell-Cafe mailing list