[Xmonad] a safer ghci prompt

Andrea Rossato mailing_list at istitutocolli.org
Fri Aug 31 13:14:46 EDT 2007


On Thu, Aug 30, 2007 at 08:21:41PM +0200, Andrea Rossato wrote:
> Hi,

Hi,

for the time being I'm working on the evaluation server. I thought to
go with socket so this is the first attempt.

Attached you'll find a new Heval. To compile:
ghc --make Heval.hs -o heval -package ghc
(requires the network package).

This one will work with telnet (I didn't write the XPrompt side yet).
To try it out:

1. run: 
./heval &

2. connect with telnet:
telnet localhost 10490

3. start interacting with your Haskell evaluator.

To quit:
:quit

To stop the server:
:stop

The server will remember bound names between sessions. So:
let f n = n ^ n
will work after :quit (but not after :stop...;-).

The server is quite basic so far: if you run something like:
let x () = x () in x ()
it will get killed after 3 seconds.

[1..] will work though.

I'm using ghciu and hs-plugins code as examples.

Please let me know what you think. Is it useful something like this
(to be run from XMonad, I mean).

Thanks for your kind attention.

Andrea

-------------- next part --------------
module Main where

import GHC
import DynFlags
import PackageConfig
import System.Environment

import Data.Char
import Data.Dynamic
import Data.List
import Data.Maybe
import Network
import System.Exit
import System.IO
import System.Random
import System.Posix.Resource

ghcPath :: String
ghcPath = "/usr/lib/ghc-6.6.1"

rlimit :: ResourceLimit
rlimit = ResourceLimit 3

main :: IO ()
main = do
  setResourceLimit ResourceCPUTime (ResourceLimits rlimit rlimit)
  defaultErrorHandler defaultDynFlags $ do
         ses <- initSession
         serverLoop ses

initSession :: IO Session
initSession = do
  ses <- newSession Interactive (Just ghcPath)
  setSessionDynFlags ses =<< getSessionDynFlags ses
  setContext ses [] [mkModule (stringToPackageId "base") (mkModuleName "Prelude")]
  return ses

serverLoop :: Session -> IO ()
serverLoop ses = do
  s <- listenOn (PortNumber 10490)
  (h, hn, pn) <- accept s
  hSetBuffering h LineBuffering
  connectionLoop ses h
  hClose h
  sClose s
  serverLoop ses

connectionLoop :: Session -> Handle -> IO ()
connectionLoop ses h = do
  exp <- hGetLine h
  runExp ses exp h

updateSession :: Session ->  [String] ->  IO ()
updateSession ses l =
    mapM_ (runStmt ses) l

exprToRun :: String -> IO String
exprToRun exp = do
  x <- sequence (take 3 (repeat $ getStdRandom (randomR (97,122)) >>= return . chr))
  return ("let { "++ x ++
          " = " ++ exp ++
          "\n} in take 2048 (show " ++ x ++
          ")")

runExp :: Session -> String -> Handle -> IO ()
runExp ses s h
    -- "let: " update session
    | "let " `isPrefixOf` s = do
  runStmt ses s
  connectionLoop ses h
    -- exit
    | ":quit" `isPrefixOf` s = return ()
    -- stop server
    | ":stop" `isPrefixOf` s = exitWith ExitSuccess
    -- something to eval
    | otherwise = do
  exp <- exprToRun s
  res <- dynCompileExpr ses exp
  case res of
    Just x -> do
        let res' = fromDynamic x :: Maybe String
        hPutStrLn h $ fromMaybe "" res'
        connectionLoop ses h
    _ -> do
        hPutStrLn h "Failed!"
        connectionLoop ses h



More information about the Xmonad mailing list