
Thanks, I'm going to have to study this a bit...
Uwe
On 2/7/08, Ryan Ingram
On 2/6/08, Uwe Hollerbach
wrote: And, coming back to my scheme interpreter, this is at least somewhat irrelevant, because, since I am in a REPL of my own devising, I'm firmly in IO-monad-land, now and forever.
This is not entirely true; a REPL can be pure.
Consider the following simple stack-based-calculator; all the IO happens within "interact", the REPL itself is pure:
import System.IO
main = hSetBuffering stdout NoBuffering >> interact replMain
replMain s = "Stack calculator\n> " ++ repl [] s
repl :: [Int] -> String -> String repl _ [] = "" repl _ ('q':_) = "" repl s ('\n':xs) = show s ++ "\n> " ++ repl s xs repl s xs@(x:_) | x >= '0' && x <= '9' = let (v, xs') = head $ reads xs in repl (v:s) xs' repl s (c:xs) | c `elem` validCommands = case command c s of Just s' -> repl s' xs Nothing -> "<stack underflow>\n" ++ repl s xs repl s (_:xs) = repl s xs -- ignore unrecognized characters
validCommands = ".d+c" command :: Char -> [Int] -> Maybe [Int] command '.' (x:xs) = Just xs command 'd' (x:xs) = Just $ x:x:xs command '+' (x:y:xs) = Just $ (x+y):xs command 'c' _ = Just [] command _ _ = Nothing
You can go further than "interact" if you want to abstract away the impurity in your system and take input from some outside process which has a limited set of impure operations. Take a look here for an example using "Prompt" (which has seen some discussion here on haskell-cafe): http://paste.lisp.org/display/53766
In that example, "guess n" is an action in the pure Prompt monad; different interpretation functions allow this monad to interact with an AI (in a semi-pure setting; it outputs strings), or with a real player via the full IO interface. A similar mechanism could be used for the scheme REPL to make it as "pure" as possible, with "getClockTime" being replaced by "prompt GetClockTime" to interact with the outside world.