<p>Just a little more interesting information: This is why impure languages like OCaml have the value restriction. Haskell doesn&#39;t need it because it is pure, but of course unsafePerformIO thwarts that.</p>
<div class="gmail_quote">On Mar 15, 2012 1:34 PM, &quot;Tillmann Rendel&quot; &lt;<a href="mailto:rendel@informatik.uni-marburg.de">rendel@informatik.uni-marburg.de</a>&gt; wrote:<br type="attribution"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Hi,<br>
<br>
this is one of the reasons why unsafePerformIO is not type-safe. Lets see what&#39;s going on by figuring out the types of the various definitions.<br>
<br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
cell = unsafePerformIO $ newIORef []<br>
</blockquote>
<br>
newIORef returns a cell which can hold values of the same type as its arguments. The type of the empty list is [a], because an empty list could be a list of arbitrary elements. So the overall type of cell is:<br>
<br>
cell :: IORef [a]<br>
<br>
cell returns a cell which can hold lists of arbitrary elements.<br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
push i = modifyIORef cell (++ [i])<br>
</blockquote>
<br>
Lets say i is of some type b. Then cell needs to hold lists of the type b. So in this use of cell, the type variable is instantiated to b, and the overall type of push is:<br>
<br>
push :: b -&gt; IO ()<br>
<br>
So push can accept arbitrary values, and appends them to the list hold by cell. (Note that ghc reports the type as (a -&gt; IO ()), but that really means the same thing as (b -&gt; IO ()).<br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
main = do<br>
  push 3<br>
</blockquote>
<br>
Here, since you call push with 3, b is chosen to be Int. After this line, the cell holds the list [3].<br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
  push &quot;x&quot;<br>
</blockquote>
<br>
Here, since you call push with &quot;x&quot;, b is chosen to be String. After this line, the cell holds the list [3, &quot;x&quot;], which is not well-typed. You tricked Haskell to produce an ill-typed list by using unsafePerformIO.<br>

<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
  readIORef cell &gt;&gt;= return<br>
</blockquote>
<br>
Here, it is not clear how you want to instantiate the type variable a in the type of cell. So lets assume that we want to return a value of type c, and instantiate a with c. So even though at this point, the list contains an Int and a String, we can (try to) extract whatever type we want from the list. Therefore, the overall type of main is:<br>

<br>
  main :: IO [c]<br>
<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
*Main&gt;  main<br>
[(),()]<br>
</blockquote>
<br>
Now once more, it is not clear how you want to instantiate c, so, by default, () is chosen. That default is only active in ghci, by the way. main will extract the Int 3 and the String &quot;x&quot; from the list, but treat them as if they were of type ().<br>

<br>
Here you get lucky: Since there&#39;s only one value of type (), ghci can show &quot;()&quot; without looking at it too deeply, so even though this program is not type-safe in a sense, it works fine in practice. But try forcing ghci to consider a more interesting type instead of ():<br>

<br>
*Main&gt; main :: IO [Int]<br>
[3,738467421]<br>
<br>
The string &quot;x&quot; is reinterpreted as a number and shown as such. You can try other types instead of Int until your ghci crashes because you access some memory you shouldn&#39;t have looked at or try to execute some random part of your memory as code.<br>

<br>
<br>
<br>
So to summarize, your code exhibits the (well-known) fact that unsafePerformIO is not type-safe, because it can be used to implement a polymorphic reference, which is a Bad Thing.<br>
<br>
  Tillmann<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
<br>
______________________________<u></u>_________________<br>
Haskell-Cafe mailing list<br>
<a href="mailto:Haskell-Cafe@haskell.org" target="_blank">Haskell-Cafe@haskell.org</a><br>
<a href="http://www.haskell.org/mailman/listinfo/haskell-cafe" target="_blank">http://www.haskell.org/<u></u>mailman/listinfo/haskell-cafe</a><br>
</blockquote></div>