[Haskell-cafe] Simple but interesting (for me) problem

Gregory Crosswhite gcross at phys.washington.edu
Wed Oct 21 15:08:16 EDT 2009


And just because this has not been explicitly stated:  it's not just  
for aesthetic reasons that you couldn't do this with a pure function,  
but because it violates the semantics and gets you the wrong result.   
So for example, if you modified Tim's code to be


import Data.IORef
import System.IO.Unsafe

mkNext :: (Num a) => IO a
mkNext = do
   ref <- newIORef 0
   return . unsafePerformIO $
          do
            modifyIORef ref (+1)
            readIORef ref

main :: IO ()
main = do
   foo <- mkNext
   print foo
   print foo
   print foo


Then the output that you will see (with GHC at least) is

1
1
1

because the compiler assumes that it only needs to evaluate foo once,  
after which it can cache the result due to assumed referential  
transparency.

- Greg



On Oct 21, 2009, at 11:40 AM, Tim Wawrzynczak wrote:

> True...here we go then:
>
> import Data.IORef
> import System.IO.Unsafe
>
> mkNext :: (Num a) => IO (IO a)
> mkNext = do
>   ref <- newIORef 0
>   return (do modifyIORef ref (+1)
>              readIORef ref)
>
> next :: IO ()
> next = do
>   foo <- mkNext
>   a <- sequence [foo,foo,foo]
>   putStrLn $ show a
>
>
> running next will print [1,2,3] which is the result of calling 'foo'  
> 3 times.
>
> But technically then, mkNext is just an IO action which returns an  
> IO action ;)
> and not a function which will return the next value each time it is  
> called,
> hence the need to extract the value from mkNext, then use it...
>
> Cheers,
> Tim
>
>
> On Wed, Oct 21, 2009 at 1:30 PM, minh thu <noteed at gmail.com> wrote:
> 2009/10/21 Tim Wawrzynczak <inforichland at gmail.com>
> >
> > Here's an example in the IO monad:
> >
> > import Data.IORef
> > import System.IO.Unsafe
> >
> > counter = unsafePerformIO $ newIORef 0
> >
> > next = do
> >   modifyIORef counter (+1)
> >   readIORef counter
> >
> > Naturally, this uses unsafePerformIO, which as you know, is not  
> kosher...
>
> But you don't close around the Ref like in your schemy example.
>
> mkNext = do
>  ref <- newIORef 0
>  return (do modifyIORef ref succ
>             readIORef ref)
>
> mimic your other code better.
>
> Cheers,
> Thu
>
> _______________________________________________
> Haskell-Cafe mailing list
> Haskell-Cafe at haskell.org
> http://www.haskell.org/mailman/listinfo/haskell-cafe

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://www.haskell.org/pipermail/haskell-cafe/attachments/20091021/dac5efec/attachment.html


More information about the Haskell-Cafe mailing list