[Haskell-cafe] Using Hint with a socket server

Daniel Gorín dgorin at dc.uba.ar
Thu Jun 17 22:05:12 EDT 2010


Hi Tom,

There is probably more than one way to do this. Did you try using the  
package hint-server? [1] It has a very simple interface: you start a  
"server" and obtain a handle;  then you can run an interpreter action   
using the handle. Something like this:

 > runIn handle (interpret msg (as :: MyType))

This expression has type IO (Either InterpreterError MyType). You can  
also run an interpreter action in the background.

Keep in mind that the ghc-api is not thread safe, though, so you  
should start only one server and put the handle in an MVar....

Hope that helps

Daniel

[1] http://hackage.haskell.org/package/hint-server

On Jun 17, 2010, at 6:35 PM, Tom Jordan wrote:

> I'm trying to receive small segments of Haskell code over a socket,  
> and be able to evaluate them in real time in GHCI.
> I've already downloaded Hint and have run the test code, and it's  
> working great.  I'm also using the socket server code from Ch.27 of  
> "Real World Haskell"
> and that is working well also.
>
>      directly below is the function from the socket server code that  
> handles the incoming messages.
>      Instead of doing this: "putStrLn msg"... I want to send  
> whatever is captured in "msg" to the GHC interpreter that is used in  
> the Hint code, something like this:  "eval msg".
>      I'm not sure how to combine both of these functionalities to  
> get them to work with each other..
>
>       -- A simple handler that prints incoming packets
>       plainHandler :: HandlerFunc
>       plainHandler addr msg =
>          putStrLn msg
>
>
> Below is the full  code for the socket server, then below that is  
> "SomeModule" used in the Hint example test below that.
>
> -- file: ch27/syslogserver.hs
> import Data.Bits
> import Network.Socket
> import Network.BSD
> import Data.List
>
> type HandlerFunc = SockAddr -> String -> IO ()
>
> serveLog :: String              -- ^ Port number or name; 514 is  
> default
>          -> HandlerFunc         -- ^ Function to handle incoming  
> messages
>          -> IO ()
> serveLog port handlerfunc = withSocketsDo $
>     do -- Look up the port.  Either raises an exception or returns
>        -- a nonempty list.
>        addrinfos <- getAddrInfo
>                     (Just (defaultHints {addrFlags = [AI_PASSIVE]}))
>                     Nothing (Just port)
>        let serveraddr = head addrinfos
>
>        -- Create a socket
>        sock <- socket (addrFamily serveraddr) Datagram defaultProtocol
>
>        -- Bind it to the address we're listening to
>        bindSocket sock (addrAddress serveraddr)
>
>        -- Loop forever processing incoming data.  Ctrl-C to abort.
>        procMessages sock
>     where procMessages sock =
>               do -- Receive one UDP packet, maximum length 1024 bytes,
>                  -- and save its content into msg and its source
>                  -- IP and port into addr
>                  (msg, _, addr) <- recvFrom sock 1024
>                  -- Handle it
>                  handlerfunc addr msg
>                  -- And process more messages
>                  procMessages sock
>
> -- A simple handler that prints incoming packets
> plainHandler :: HandlerFunc
> plainHandler addr msg =
>     putStrLn msg
>
>
> -- main = serveLog "8008" plainHandler
> ----------------------------------------------------------------------------------------------------------------
>
> module SomeModule(g, h) where
>
> f = head
>
> g = f [f]
>
> h = f
>
> ----------------------------------------------------------------------------------------------------------------
>
> import Control.Monad
> import Language.Haskell.Interpreter
>
> main :: IO ()
> main = do r <- runInterpreter testHint
>           case r of
>             Left err -> printInterpreterError err
>             Right () -> putStrLn "that's all folks"
>
> -- observe that Interpreter () is an alias for InterpreterT IO ()
> testHint :: Interpreter ()
> testHint =
>     do
>       say "Load SomeModule.hs"
>       loadModules ["SomeModule.hs"]
>       --
>       say "Put the Prelude, Data.Map and *SomeModule in scope"
>       say "Data.Map is qualified as M!"
>       setTopLevelModules ["SomeModule"]
>       setImportsQ [("Prelude", Nothing), ("Data.Map", Just "M")]
>       --
>       say "Now we can query the type of an expression"
>       let expr1 = "M.singleton (f, g, h, 42)"
>       say $ "e.g. typeOf " ++ expr1
>       say =<< typeOf expr1
>       --
>       say $ "Observe that f, g and h are defined in SomeModule.hs, "  
> ++
>             "but f is not exported. Let's check it..."
>       exports <- getModuleExports "SomeModule"
>       say (show exports)
>       --
>       say "We can also evaluate an expression; the result will be a  
> string"
>       let expr2 = "length $ concat [[f,g],[h]]"
>       say $ concat ["e.g. eval ", show expr1]
>       a <- eval expr2
>       say (show a)
>       --
>       say "Or we can interpret it as a proper, say, int value!"
>       a_int <- interpret expr2 (as :: Int)
>       say (show a_int)
>       --
>       say "This works for any monomorphic type, even for function  
> types"
>       let expr3 = "\\(Just x) -> succ x"
>       say $ "e.g. we interpret " ++ expr3 ++
>             " with type Maybe Int -> Int and apply it on Just 7"
>       fun <- interpret expr3 (as :: Maybe Int -> Int)
>       say . show $ fun (Just 7)
>       --
>       say "And sometimes we can even use the type system to infer  
> the expected type (eg Maybe Bool -> Bool)!"
>       bool_val <- (interpret expr3 infer `ap` (return $ Just False))
>       say (show $ not bool_val)
>       --
>       say "Here we evaluate an expression of type string, that when  
> evaluated (again) leads to a string"
>       res <- interpret "head $ map show [\"Worked!\", \"Didn't work 
> \"]" infer >>= flip interpret infer
>       say res
>
>
> say :: String -> Interpreter ()
> say = liftIO . putStrLn
>
> printInterpreterError :: InterpreterError -> IO ()
> printInterpreterError e = putStrLn $ "Ups... " ++ (show e)
> _______________________________________________
> Haskell-Cafe mailing list
> Haskell-Cafe at haskell.org
> http://www.haskell.org/mailman/listinfo/haskell-cafe



More information about the Haskell-Cafe mailing list