Haldean Brown
Haldean Brown

Reputation: 12721

Lisp-like configuration using code in Haskell

I'm writing a raytracer in Haskell and, currently, I define my scene in code like so:

(Scene [(Sphere (Vec3 1 0 0) 4 (PhongMaterial (color 1 0 0) (color 1 1 1) 4))]
       [(PhongLight (Vec3 0 0 0) (color 1 1 1) (color 1 1 1))])

This works really well in terms of expressivity, and it's great because I don't have to write any sort of parser, but it means that I have to recompile every time I want to render a different scene. I've come to Haskell through Lisp, where this would be simple (load a file, eval the contents and then render the result) but I recognize that Haskell has traits that makes that, if not impossible, then very difficult.

Do any of you much more experienced Haskellers have any suggestions for the best way to go around solving this? In an ideal world, I'd have some file external to my code that defined the scene in Haskell syntax which I could load; in the least-ideal world possible I'd be writing a parser in Parsec. Thanks!

Upvotes: 6

Views: 226

Answers (3)

aleator
aleator

Reputation: 4486

How about using a haskell interpreter like Hint? Admittedly this is not as easy as in lisp and you need to be extra careful that you compile your renderer with the same modules as you use for describing your scenes, but still it could work ok, even though it isn't really a Haskell way of doing things.

 main :: IO ()
 main = do 
      [a] <- getArgs
      r <- runInterpreter (loadScene a)
      case r of
        Left err -> printInterpreterError err
        Right scene -> raytrace scene

 loadScene :: Filepath -> Interpreter ()
 loadScene fn = do
      loadModules [fn]
      eval "name_of_variable_describing_scene_in_my_source"

Upvotes: 0

Matt Fenwick
Matt Fenwick

Reputation: 49095

If you make sure all of your data are instances of Read (... deriving Read), then you can just read them :: Withatypeifnecessary.

An intermediate solution would be to use json; parsing is easier than using Parsec, but of course it's a bit harder than just read-ing in code.


Update: if there are non-constructor functions, the read approach won't work.

Upvotes: 7

Jeff Foster
Jeff Foster

Reputation: 44706

In this case, could you simply use read (assuming that everything does deriving Read). It's obviously a little clunky but chances are it would probably work (and it's less work than going down the parsec route).

Upvotes: 1

Related Questions