
This is one good reason they have to be protected by MVars
Forgive my stupidity, but arn't the MVar operations (takeMVar, putMVar) IO operation, therefore the locks must be in the IO monad, therefore the code acting on the DiffArray should be in the IO monad... otherwise they can't use the MVar calls?
DiffArray is an example of a good use for unsafePerformIO: it uses imperative operations to implement a pure API. The DiffArray is made of mutable objects under the hood, but as far as the programmer is concerned it behaves just like a pure Array. Cheers, Simon

Simon Marlow wrote:
DiffArray is an example of a good use for unsafePerformIO: it uses imperative operations to implement a pure API. The DiffArray is made of mutable objects under the hood, but as far as the programmer is concerned it behaves just like a pure Array.
I'd like to ask a general question about unsafePerformIO: What exactly does unsafe mean? Just "impure" or rather "may lead to all kinds of problems, you better don't use this"? After a few experiments, I stopped using unsafePerformIO for disk access because it just segfaulted too much. I'm not 100% sure if unsafePerformIO was the culprit though; I did a lot of restructuring while eliminating it, so I might have inadvertently removed the real cause for the crashes in the process. -Stefan

Stefan Reich wrote:
DiffArray is an example of a good use for unsafePerformIO: it uses imperative operations to implement a pure API. The DiffArray is made of mutable objects under the hood, but as far as the programmer is concerned it behaves just like a pure Array.
I'd like to ask a general question about unsafePerformIO: What exactly does unsafe mean? Just "impure" or rather "may lead to all kinds of problems, you better don't use this"?
Essentially both. Haskell assumes purity (referential transparency),
so impurity is likely to result in "all kinds of problems".
If you think of the IO monad as a state transformer, i.e.
IO a = World -> (World, a)
unsafePerformIO basically applies the transformation to whichever
World value happens to be available at the time (i.e. the current
system state, where "current" is unspecified), and that depends upon
the details of the evaluation mechanism.
Using unsafePerformIO is safe if the transformer generates the same
result result for all possible World values. If it generates different
results for different World values, you risk running into problems.
Note: even if you are willing to accept one of many possible "valid"
values, you need to allow for the fact that the expression may be
evaluated multiple times. E.g. if you have:
let x = unsafePerformIO foo
where foo may produce different values, you could find that x /= x.
The opposite problem is also possible, i.e. that distinct occurrences
of the same expression could be merged. A common example is in
attempting to create "global variables":
x, y :: IORef Int
x = unsafePerformIO $ newIORef 0
y = unsafePerformIO $ newIORef 0
Due to optimisation, x any y may end up referring to the same IORef.
In short: Haskell assumes referential transparency; if you break it,
all bets are off.
--
Glynn Clements

Glynn Clements
Stefan Reich wrote:
I'd like to ask a general question about unsafePerformIO: What exactly does unsafe mean? Just "impure" or rather "may lead to all kinds of problems, you better don't use this"?
Essentially both. Haskell assumes purity (referential transparency), so impurity is likely to result in "all kinds of problems".
Here's a thing that can easily happen: my_trace = unsafePerformIO . putStrLn f x = trace "f called" `seq` .... Now, when f is evaluated, it will print the message. However, when f is re-evaluated (normally with a different x), no message is printed! Why? Because the system will optimize by realizing that 'trace' is called with the same argument, and it will just keep the old value (). This behaviour depends on the level of optimization in your compiler/interpreter, feel free to experiment! The fix is of course to do my_trace ("f called with arg "++show x) `seq` ... which will usually do what you expect. Moral: unsafe means you can use it, but it doesn't give you any complaining rights when it doesn't do what you think it should do. (Sometimes in my darker moments, I feel we might bite the bullet, and call the whole thing unsafeHaskell, and be done with it :-) -kzm PS: trace is defined in the libraries, not sure if it behaves more reasonable in this respect. -- If I haven't seen further, it is by standing in the footprints of giants
participants (4)
-
Glynn Clements
-
ketil+haskell@ii.uib.no
-
Simon Marlow
-
Stefan Reich