[Haskell] Using unsafePerformIO safely
jochem at functor.nl
Wed Jun 24 18:34:17 EDT 2009
Hector Guilarte wrote:
> I made a GCL compiler using Alex and Happy and now I'm making the
> interpreter to that program. Here's the deal:
> First of all, I'm no expert in the usage of monads. Now:
> Whenever a "show" instruction is found in any GCL program while the
> interpretation is being done it is supposed to print on the stdout the
> string or the aritmetic expresion it was called with, so I guessed I need to
> run an IO operation and continue the interpretation of my program. I managed
> to do this using unsafePerformIO and `seq` like is shown below. My question
> is: Is it safe to use it this way? So far it is working great, but I need to
> be sure I'm using it in a "safe" way. Like I said, I'm no expert in monads
> and the System.IO.Unsafe documentation says:
> *unsafePerformIO* ::
> -> a
> This is the "back door" into the
> to be performed at any time. For this to be safe, the
> should be free of side effects and independent of its
> I don't know if the IO computation I'm doing is free of side effects and
> independent of its enviroment :s. (is just hPutStr stdout ....)
Well, writing to the standard output is certainly a side effect. (This
does not mean that you cannot use unsafePerformIO. The compiler,
however, may assume that any value is free from side effects. This means
that you could get, in theory, less or more output from your program
than you want. In this sense it is not "safe".)
> Also I've read something about my code not being executed for sure or
> something like that. Can somebody check the code and tell me if I'm "safe"
> with it?
It's "safe" in the sense that it probably won't blow up your computer.
It may also work. On the other hand, I would not recommend using
unsafePerformIO in this way.
I see two possibilities for resolving this issue:
* (ugly) run your GCL (Guarded Command Language?) interpreter in the IO
monad, and using "print"/"putStr"/... whenever you encounter a 'show'
statement in the GCL program.
* (nicer/Haskellier) adapt your interpreter such that it returns a list
of Strings to output. You have then a purely functional interpreter, and
in the main function of your program you can print this list. This will
be lazily evaluated as the GCL program runs. You now have a very nice
separation of clean, pure code, and impure code in the IO monad (your
"main" function, which can be pretty small in your case). To avoid
boilerplate, you can use the Writer monad, for example, but others may
have better suggestions.
Jochem Berndsen | jochem at functor.nl
More information about the Haskell