Interpreting synchronized streams (pre-IO monad Haskell)

Heλλo! 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! Jiri [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

You want unsafeInterleaveIO. That will allow you to build the list of responses as a list of thunks, each of which reads a request and yields a new response when forced.
On Feb 13, 2020, at 06:10, Jiri Jakes
wrote: Heλλo!
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!
Jiri
[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 _______________________________________________ Haskell-Cafe mailing list To (un)subscribe, modify options or view archives go to: http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe Only members subscribed via the mailman list are allowed to post.
participants (2)
-
Alexis King
-
Jiri Jakes