[Haskell-cafe] Re: do
Brandon S. Allbery KF8NH
allbery at ece.cmu.edu
Mon Oct 15 21:18:30 EDT 2007
On Oct 15, 2007, at 21:01 , Ryan Ingram wrote:
> Oops, I read too fast, you mentioned that as #1.
>
> On 10/15/07, ChrisK <haskell at list.mightyreason.com> wrote:
>> Also you need to get you hand on State# RealWorld either
>> (1) Honestly, by wrapping your code in IO again and using it
>> normally
>
> Silly me.
That makes two of us; my (4) is in fact his (1), I misunderstood the
"wrapping your code in IO again".
For those trying to follow along with all this silliness, the secret
to making this work is defining a runIO function --- which is *not*
the same as unsafePerformIO, because that invokes the internal
RealWorld# constructor to inject a "fresh" State# RealWorld, whereas
we're using the one that we were legitimately passed:
runIO :: IO a -> State# RealWorld -> (# State#
RealWorld,a #)
runIO (IO f) s = lazy (f s)
(See libraries/base/GHC/IOBase.lhs for why we need the GHC builtin
"lazy" there.)
The reason for this is that IO is a "state-like" type:
newtype IO a = IO (State# RealWorld -> (# State# RealWorld,a #))
Which is to say, it is a wrapper around a function which accepts a
state and returns a "modified" (in our case, actually just passed
through without even looking at it) state along with the result of a
computation. The runIO function is just runState specialized to this
newtype. (Because you can't pattern match on (IO (s -> (# s,a #)))
in a function definition.)
I'm working on a "simple" example of how to do this without treating
IO as a monad. So far it's proving a very concrete demonstration to
me of why you do *not* want to do it this way, but instead should
consider the monad your friend. :)
--
brandon s. allbery [solaris,freebsd,perl,pugs,haskell] allbery at kf8nh.com
system administrator [openafs,heimdal,too many hats] allbery at ece.cmu.edu
electrical and computer engineering, carnegie mellon university KF8NH
More information about the Haskell-Cafe
mailing list