3

I know as a fact, that we cant implement an IO monad independently, but I dont know why exactly. This code is an attempt to implement an imperative paradigm using functional language. Can you explain the difference between this example and true IO? It looks like function main implements the correct action order and remains lazy.

import System.IO.Unsafe   

data Io a = Io a 

runIO :: Io a -> a
runIO (Io a) = a

instance Monad Io where  
 return x = Io x
 Io a >>= f = f a

-- internal side effect function 
output :: Show a => a -> Io () 
output s  = return $! unsafePerformIO $ print s

----------------------------------------------------------------

mainIO :: Io ()                             
mainIO = do output "A"  
            b <- return "B"
            output b     
            output b 
            x <- return (undefined :: String)
            return undefined
            output "C"    
            head [output "C", output "C"]
            output x  
            output "D"

test = runIO mainIO 

output:

"A"
"B"
"B"
"C"
"C"
<interactive>: Prelude.undefined
Don Stewart
  • 137,316
  • 36
  • 365
  • 468
user1374768
  • 288
  • 2
  • 11

1 Answers1

11

I'm not sure what you're trying to show. You've embedded an encoding of IO in Haskell, using the existing implementation of IO as a target.

The key is your use of unsafePerformIO and print --- primitives you're borrowing from the other IO system.

Consider: what if you didn't have any other IO system to lean on. So no print or other way to call primitive IO functions. How would you implement IO?

So while you can implement the IO abstraction many ways in Haskell, you always have to fall on new runtime primitive functions to actually call into the operating system to do real IO. That's the bit that can't be implemented in Haskell natively.


As a reference , see the PhD thesis "A Functional Specification of Effects", Wouter Swierstra, which gives an overview of various ways IO and other effects have been encoded in Haskell, and defines a specification of IO as a purely functional data type (kind of an extension of what you've done).

enter image description here

atravers
  • 455
  • 4
  • 8
Don Stewart
  • 137,316
  • 36
  • 365
  • 468
  • Thanks for reply and the reference! Im new on this site, so if I ask some questions later in this topic will somebody notice it? Or will it be better to create a new topic? – user1374768 May 04 '12 at 13:49
  • By the way, my question appeared after reading this tutorial http://www.haskell.org/haskellwiki/IO_inside and this paper http://webcache.googleusercontent.com/search?q=cache:ry-JwgJnib0J:research.microsoft.com/pubs/67066/imperative.ps.z+hl=ru(a,RealWorld) – user1374768 May 04 '12 at 13:49
  • An IO type defined as RealWorld->(a,RealWorld) is used here, so an action sequence is realized using the fake parameter RealWorld. But IMHO this model is impossible in pure language without outer compiler hacks. So I wonder why this implementation is used, hope that pdf has more clearly explanation. – user1374768 May 04 '12 at 13:51
  • @user1374768: It's best to ask a new question. – Antal Spector-Zabusky May 06 '12 at 06:44