[Haskell] Simple IO Regions

oleg at pobox.com oleg at pobox.com
Thu Jan 19 07:55:04 EST 2006

Simon Peyton-Jones wrote:

> Previously I've thought of using a nested tuple type
> 	(m1, (m2, (m3 ())))

That was my thought too. But then we need the comparison operation on
those 'm' (which are actually type eigen-variables). Not that it can't
be done (it can, and several examples prove that). But it requires a
little bit too many extensions. It appears there is a way to move the
whole burden of maintaining the set of types (which become the set of
constraints) to the typechecker. That is, to you...

> Why do you need the
> 	instance IN () b
> ?

Don't we need at least one instance in a class so that the typechecker
could resolve the constraint?

Dominic Steinitz wrote:
> Can someone give an explanation of how the marks get built up?

Suppose we have a class TypeEq a b so that the constraint TypeEq holds
whenever a and b are the same. Then the type Int and the type
	TypeEq a Int => a
are kind of equivalent, right? The HList library plays many tricks
like that. The idea is that we can replace a definite type with a type
variable subject to some constraint (which we can fix later on). 
In some respects, constraints are more convenient: they float, their
order does not matter, their duplicates are automatically
eliminated. Just what we need to build a set...
It ``follows'' then that instead of building the union of types, we
can build the union of constraints. The latter operation is trivial:
the typechecker does that all the time. If we restrict the scope of
the type variable by quantification, the scope of the corresponding
constraint is likewise restricted. The quantification also builds
eigen-variables (which are distinct from anything else) -- so we get
'gensym' on the type level for free. That is all there is to it...

Chris Kuklewicz wrote:
> I tweaked the IORegions code using some other ideas from the thread.
> qGetChar was just a demo, and has been replaced by liftH, liftH2, and
> liftH3 which should cover all the System.IO hFoo functions.

As Andrew Pimlott has just pointed out on Haskell cafe, liftH
functions should not be exported!

The functions within the IORegions module have unrestricted access to
the naked handle. They have to be careful and trusted:

	-- do not leak the unwrapped handle

	-- do not close the handle
	   (if the handle really needs to be closed,
	    one better just throw an exception or error)

Because liftH accepts an _arbitrary_ function on handles, it
essentially extends the trust to anyone outside of IORegions -- which
defeats the latter's purpose. True, liftH functions are convenient --
but they must be used _inside_ of the module, to build qGetChar,
qPutChar, etc. functions. It is the latter that can be exported.

The idea of regions is that not all operations on handles are
`safe'. Thus we need a way to specifically enumerate which are those
primitive operations that safe. Enumerating lifted versions of
getChar, putChar, etc. in the export list of IORegions is that
enumeration. I'm afraid we have a circumstance where genericity is not
a virtue.

More information about the Haskell mailing list