Just a little more interesting information: This is why impure languages like OCaml have the value restriction. Haskell doesn't need it because it is pure, but of course unsafePerformIO thwarts that. On Mar 15, 2012 1:34 PM, "Tillmann Rendel" <ren...@informatik.uni-marburg.de> wrote:
> Hi, > > this is one of the reasons why unsafePerformIO is not type-safe. Lets see > what's going on by figuring out the types of the various definitions. > > > cell = unsafePerformIO $ newIORef [] >> > > 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: > > cell :: IORef [a] > > cell returns a cell which can hold lists of arbitrary elements. > > push i = modifyIORef cell (++ [i]) >> > > 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: > > push :: b -> IO () > > So push can accept arbitrary values, and appends them to the list hold by > cell. (Note that ghc reports the type as (a -> IO ()), but that really > means the same thing as (b -> IO ()). > > main = do >> push 3 >> > > Here, since you call push with 3, b is chosen to be Int. After this line, > the cell holds the list [3]. > > push "x" >> > > Here, since you call push with "x", b is chosen to be String. After this > line, the cell holds the list [3, "x"], which is not well-typed. You > tricked Haskell to produce an ill-typed list by using unsafePerformIO. > > readIORef cell >>= return >> > > 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: > > main :: IO [c] > > *Main> main >> [(),()] >> > > 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 "x" from the list, but treat > them as if they were of type (). > > Here you get lucky: Since there's only one value of type (), ghci can show > "()" 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 (): > > *Main> main :: IO [Int] > [3,738467421] > > The string "x" 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't have looked at or try to execute some random part of > your memory as code. > > > > 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. > > Tillmann > > > > > > > > > ______________________________**_________________ > Haskell-Cafe mailing list > Haskell-Cafe@haskell.org > http://www.haskell.org/**mailman/listinfo/haskell-cafe<http://www.haskell.org/mailman/listinfo/haskell-cafe> >
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe