<div dir="ltr">Thanks to everyone for the suggestions, I'm reading up on Monad transformers and I'll see where that takes me.<div><br></div><div>Graham, I was also curious why your parsers return SwishStateIO ()? When I was thinking about the design, it made sense to me to separate the parser from the interperter, that is my parsers return Command, where Command is defined like this:</div><div><br></div><div><div>data Command = Line D3Coord D3Coord D3Coord D3Coord D3Coord D3Coord</div><div> | Circle D3Coord D3Coord D3Coord</div><div> | Hermite D3Coord D3Coord D3Coord D3Coord D3Coord D3Coord D3Coord D3Coord</div><div> | Bezier D3Coord D3Coord D3Coord D3Coord D3Coord D3Coord D3Coord D3Coord</div><div> | Identity</div><div> | Scale D3Coord D3Coord D3Coord</div><div> | Translate D3Coord D3Coord D3Coord</div><div> | RotateX D3Coord</div><div> | RotateY D3Coord</div><div> | RotateZ D3Coord</div><div> | Apply</div><div> | Display</div><div> | Save FilePath</div></div><div><br></div><div>And then, my interpreter will consume a [Command] and produce some sort of Monad. What are the advantages of doing it your way?</div><div><br></div><div>Thanks,</div><div>Jake</div><br><div class="gmail_quote"><div dir="ltr">On Thu, Apr 7, 2016 at 1:05 PM Graham Klyne <<a href="mailto:gk@ninebynine.org" target="_blank">gk@ninebynine.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">On 07/04/2016 15:29, Jake wrote:> I'm currently in a graphics class where, in<br>
order to provide a standard<br>
> interface to all of our graphics libraries, we have to process small<br>
> scripts that look like this:<br>
[...]<br>
<br>
I did something like this for my Swish system, some time ago.<br>
<br>
Several others adapted the software, and most recently Doug Burke put the code<br>
in BitBucket.<br>
<br>
Relevant modules are<br>
<br>
"Scrips.hs" - originally a "parsec" based parser, but now something else, parses<br>
script source and returns a "SwishStateIO" monad.<br>
<br>
-<br>
<a href="https://bitbucket.org/doug_burke/swish/src/8f72b52f02fb540e8e1c26caa5036920a9ff31da/src/Swish/Script.hs?at=default&fileviewer=file-view-default" rel="noreferrer" target="_blank">https://bitbucket.org/doug_burke/swish/src/8f72b52f02fb540e8e1c26caa5036920a9ff31da/src/Swish/Script.hs?at=default&fileviewer=file-view-default</a><br>
<br>
"Monad.hs" - defines the "SwishStateIO" monad, and defines implementations of<br>
the primitive functions of the scripting language. It's a long time since I<br>
looked at this, but I think a key part of the definition is:<br>
<br>
type SwishStateIO a = StateT SwishState IO a<br>
<br>
which (if I get this right) wraps the basic state and associated transformation<br>
functions in an IO monad.<br>
<br>
-<br>
<a href="https://bitbucket.org/doug_burke/swish/src/8f72b52f02fb540e8e1c26caa5036920a9ff31da/src/Swish/Monad.hs?at=default&fileviewer=file-view-default" rel="noreferrer" target="_blank">https://bitbucket.org/doug_burke/swish/src/8f72b52f02fb540e8e1c26caa5036920a9ff31da/src/Swish/Monad.hs?at=default&fileviewer=file-view-default</a><br>
<br>
The "compiled" script (SwishStateIO value) is run by applying it to an initial<br>
state; the module that pulls it all together is:<br>
<br>
-<br>
<a href="https://bitbucket.org/doug_burke/swish/src/8f72b52f02fb540e8e1c26caa5036920a9ff31da/src/Swish.hs?at=default&fileviewer=file-view-default" rel="noreferrer" target="_blank">https://bitbucket.org/doug_burke/swish/src/8f72b52f02fb540e8e1c26caa5036920a9ff31da/src/Swish.hs?at=default&fileviewer=file-view-default</a><br>
<br>
...<br>
<br>
I'm not sure if any of this makes any sense, but the key idea for me, way back<br>
when, was the capability to compile a script directly to a monadic function that<br>
could then be executed by function application to an initial state (in this<br>
case, using execStateT).<br>
<br>
#g<br>
--<br>
<br>
<br>
On 07/04/2016 15:29, Jake wrote:<br>
> I'm currently in a graphics class where, in order to provide a standard<br>
> interface to all of our graphics libraries, we have to process small<br>
> scripts that look like this:<br>
><br>
> line<br>
> 0 0 0 1 1 1<br>
> circle<br>
> 0 0 10<br>
> scale<br>
> 0 0 3<br>
> save<br>
> pic.png<br>
><br>
> I successfully wrote a parser with attoparsec that parses the file into a<br>
> list of Commands. Now I'm trying to process that list to produce an IO<br>
> action, and I thought the State monad would be useful to keep track of the<br>
> persistent state of the shapes to draw and the transformations on them.<br>
><br>
> I'm confused about how exactly to do this though. What should the type of<br>
> my State be? Right now I have an execute function that is<br>
> execute :: Command -> State ParseState (IO ())<br>
> where ParseState is a tuple of stuff. ParseState also includes an IO ()<br>
> because I wanted to be able to create multiple pictures one after another,<br>
> and I couldn't figure out how to access the previous result value from<br>
> State to add on to it in the next one.<br>
><br>
> So can anyone offer advice on my specific situation, or maybe a simpler<br>
> example of how to go about writing an interpreter with the State monad?<br>
><br>
> Thanks,<br>
> Jake<br>
><br>
><br>
><br>
> _______________________________________________<br>
> Haskell-Cafe mailing list<br>
> <a href="mailto:Haskell-Cafe@haskell.org" target="_blank">Haskell-Cafe@haskell.org</a><br>
> <a href="http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe" rel="noreferrer" target="_blank">http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe</a><br>
><br>
_______________________________________________<br>
Haskell-Cafe mailing list<br>
<a href="mailto:Haskell-Cafe@haskell.org" target="_blank">Haskell-Cafe@haskell.org</a><br>
<a href="http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe" rel="noreferrer" target="_blank">http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe</a><br>
</blockquote></div></div>