[Yhc] YHC.Primitive;_E

Tom Shackell shackell at cs.york.ac.uk
Thu Feb 21 03:43:45 EST 2008


Hi Tom,


 > To get the hang of using Yhc.Core, I'm writing a little haskell
 > interpreter.  The interpreter errors out when ever it comes across an
 > unknown primitive.  The first such primitive I had to implement was
 > SEQ.  Now I'm on to YHC.Primitive;_E.
 >
 > What is the meaning of this type?

_E is a box to protect a value from evaluation. It comes about because 
all primitive functions are strict in all arguments, this is correct for 
the vast majority of primitives. However for a few primitives we don't 
want the primitive to evaluate the argument, one such example is the 
"primSpawnProcess" primitive.

   foreign import primitive primSpawnProcess :: _E a -> IO ThreadId

primSpawnProcess takes a closure and evaluates that closure in a new 
thread, returning the unique Id of the thread it created. 
primSpawnProcess can't evaluate it's argument, because if it did the 
closure to be run in a new thread wouldn't be run in a new thread, it 
would be run in this thread!

primSpawnProcess is used to implement forkIO.

    forkIO :: IO () -> IO ThreadId
    forkIO action = primSpawnProcess boxed
	where	
	boxed = _E (unsafePerformIO action)

Thus it is passed the closure inside the _E box. When primSpawnProcess 
comes to evaluate it's argument it sees the box, and notes that it is
already evaluated. Thus the closure is passed into primSpawnProcess 
unevaluated, inside it's protective box.

Another place that _E is used like this (which you might just come 
across) is in the implementation of Data.Array. The crucial point here 
is that you are allowed to put unevaluated values inside arrays, however 
the array is accessed entirely via primitives, hence the need to box the 
values that are being put in an array.

 > Is there a place where these
 > primitive types are defined?  When I print the coreDatas I see:
 >
 > data YHC.Primitive;_E b =
 >       YHC.Primitive;_E b
 >

This is the correct definition of _E, it is just a box. As might be 
expected from "YHC.Primitive;_E" it is defined in YHC/Primitive.hs.

 > When I print coreFuncs, I see no Case expressions that could extract
 > data put into _E.

Indeed this is because the primSpawnProcess function itself (which is 
written in C) takes the closure out of the box. After pulling it out of 
the box it does the necessary magic to ensure that the closure is 
evaluated inside a new thread.

The other major place that _E is used is in the IO monad. This is 
probably where you've actually managed to use _E, since I'm guessing 
you're probably not using the concurrency features ;)

The IO monad is defined as:

   newtype IO a = IO (World -> _E a)

again here the _E is used to prevent evaluation, though why it's 
necessary is a fairly complex issue.

Unlike with the other uses of _E, in the IO monad _E is just a normal 
(if somewhat boring) datatype, and it is cased on like any other 
datatype. Both cases involving _E are in Prelude.hs: one in ">>=", 
another in the "showsType" method of the Show instance for the IO monad.


Hope that helps :)


Tom


More information about the Yhc mailing list