
I noticed a coreFunc has an extra argument and I'm not sure where it's coming from. For example if I compile: main :: IO () main = return () and print out the coreFuncs and coreDatas I get: Main;main = Prelude;YHC.Internal.IO;Prelude.Monad;return Prelude;() Prelude;1807_ioReturn v25601 v25602 = YHC.Primitive;_E v25601 Prelude;YHC.Internal.IO;Prelude.Monad;return v25600 = Prelude;1807_ioReturn v25600 main = Main;main data YHC.Primitive;_E b = YHC.Primitive;_E b data Prelude;() = Prelude;() Why does Prelude;1807_ioReturn include an extra argument (v25602) that is not used? If I informally type check this by hand, I get a contradiction: main :: IO () Main;main :: IO () Prelude;YHC.Internal.IO;Prelude.Monad;return :: a -> IO a Prelude;YHC.Internal.IO;Prelude.Monad;return = Prelude;1807_ioReturn Therefore if follows: Prelude;1807_ioReturn :: a -> IO a But the Prelude;1807_ioReturn definition has type: Prelude;1807_ioReturn :: a -> b -> YHC.Primitive;_E a What am I missing here? Am I to interpret this as meaning: b -> YHC.Primitive;_E a == IO a ? Thanks for any help! -Tom

At Mon, 3 Mar 2008 21:38:51 -0600, Tom Hawkins wrote:
What am I missing here? Am I to interpret this as meaning:
b -> YHC.Primitive;_E a == IO a ?
Yes. From src/packages/yhc-base-1.0/YHC/Internal.hs: data World = World newtype IO a = IO (World -> _E a) Remember that the 'newtype' is coverted to a type alias after type checking. So: main :: IO () is really, main :: World -> _E () and when the 'compiler' calls main it actually passes in a World value. (Or at least, in my yca2swf compiler I believe I do). I believe 'tackling the awkward squad' explains the World parameter. http://research.microsoft.com/~simonpj/papers/marktoberdorf/ hth, j.

I believe 'tackling the awkward squad' explains the World parameter.
http://research.microsoft.com/~simonpj/papers/marktoberdorf/
Indeed this is the 'World' parameter. It's quite easy to see why it's needed. Image the getChar function ... getChar :: IO Char if we imagine that the World parameter wasn't present, this would make the type of getChar. getChar :: _E Char Since _E is just a box this is basically the same as. getChar :: Char Since this doesn't take any arguments it's a CAF, i.e. a constant value. Since it's constant, every call to getChar would always return the same character! When we add the World parameter we turn getChar into. getChar :: World -> Char Now getChar takes an argument, so its value is no longer constant (its value can vary depending on the argument). Haskell neither knows, nor cares, that getChar doesn't even look at the World argument. As far as Haskell is concerned getChar has an argument so Haskell can't treat it like a constant. In other words, it's all some nasty trickery to make impure functions work correctly in Haskell ;) Hope that explains it :) Tom

Thanks Tom and Jeremy, this helps a lot. Actually, Tom I see you
spelled this out for me a couple weeks ago in an earlier post. Sorry,
I'm a bit slow.
So am I correct in saying that World is never reference in the
program, it's only used to emulate imperative actions?
-Tom
On 3/4/08, Thomas Shackell
I believe 'tackling the awkward squad' explains the World parameter.
http://research.microsoft.com/~simonpj/papers/marktoberdorf/
Indeed this is the 'World' parameter. It's quite easy to see why it's needed. Image the getChar function ...
getChar :: IO Char
if we imagine that the World parameter wasn't present, this would make the type of getChar.
getChar :: _E Char
Since _E is just a box this is basically the same as.
getChar :: Char
Since this doesn't take any arguments it's a CAF, i.e. a constant value. Since it's constant, every call to getChar would always return the same character!
When we add the World parameter we turn getChar into.
getChar :: World -> Char
Now getChar takes an argument, so its value is no longer constant (its value can vary depending on the argument). Haskell neither knows, nor cares, that getChar doesn't even look at the World argument. As far as Haskell is concerned getChar has an argument so Haskell can't treat it like a constant.
In other words, it's all some nasty trickery to make impure functions work correctly in Haskell ;)
Hope that explains it :)
Tom

Tom Hawkins wrote:
Thanks Tom and Jeremy, this helps a lot. Actually, Tom I see you spelled this out for me a couple weeks ago in an earlier post. Sorry, I'm a bit slow.
Not at all, it's actually quite complex. It took me a couple of attempts to get the IO type right. It has many funny features, and the reasons that some of them are there is quite subtle :)
So am I correct in saying that World is never reference in the program, it's only used to emulate imperative actions?
The value of World comes up in only two places that I know of. The first is in the startup code. When the interpreter starts it calls the YHC._Driver._driver function, passing it a value of type World and the 'main' function to evaluate. _driver :: World -> IO () -> a In fact _driver doesn't even use the World value it is passed, its existence in that function is entirely historical and it could be removed if anyone could be bothered :) The second, and more useful, example is unsafePerformIO. Defined in YHC.Internal. unsafePerformIO :: IO a -> a unsafePerformIO (IO f) = case f World of _E x -> x This takes an IO action, unpacks it, applies World to it (which the IO action will never look at) and then gets the result. So World is created, and passed as an argument, but (as far as I know) it is never cased on. It's also only ever used inside the IO monad. Hope that helps :) Tom

Tom Shackell wrote:
The value of World comes up in only two places that I know of.
Ah I lie, the final use of World is in the Show instance of the IO Monad. instance (Show a) => Show (IO a) where ... showsType (IO fta) = showString "(IO " . showsType ta . showChar ')' where (_E ta) = fta World Interestingly this applies World to the IO action, however, since the only thing that is done with the result is 'showsType' the computation is never actually evaluated (since you don't need to evaluate it to know its type). Though why this doesn't just use unsafePerformIO I don't know ... showsType io = showString "(IO " . showsType a . showChar ')' where a = unsafePerformIO io This would work just as well. *shrugs* Yhc has quite a lot of historical carry-overs from nhc98 :) Cheers Tom

Hi
showsType io = showString "(IO " . showsType a . showChar ')' where a = unsafePerformIO io
You don't even need unsafePerformIO! All you need is a proxy a which has the right type, this can be done by doing: showsType io = showString "(IO " . showsType a . showChar ')' where a = undefined b = asTypeOf (return a) io i.e. instead of unwrapping the io, you wrap up the a, and demand it has the same type as io. Same result, but now entirely "safe". [Note: entirely untested, but the idea should be sound] Thanks Neil

Neil Mitchell wrote:
You don't even need unsafePerformIO! All you need is a proxy a which has the right type, this can be done by doing:
showsType io = showString "(IO " . showsType a . showChar ')' where a = undefined b = asTypeOf (return a) io
That works too, though it still relies on showsType not evaluating it's argument - since otherwise it'll eval undefined :S Tom

Hi
showsType io = showString "(IO " . showsType a . showChar ')' where a = undefined b = asTypeOf (return a) io
That works too, though it still relies on showsType not evaluating it's argument - since otherwise it'll eval undefined :S
Of course, but the advantage is that if it fails to work the side effect is _|_, rather than (potentially) rooting your computer. I'm thinking for the day when we have yhi --safe to not run IO computations. i.e. showType (deleteFile "/usr/shackell/thesis.tex") :-) Thanks Neil
participants (5)
-
Jeremy Shaw
-
Neil Mitchell
-
Thomas Shackell
-
Tom Hawkins
-
Tom Shackell