[Haskell] Re: Implicit return values

Ben Rudiak-Gould benrg at dark.darkweb.com
Sun Jan 25 17:10:55 EST 2004

I wrote:

> It should be possible to implicitly return values which are not instances
> of Monoid: the compiler errors out if it ever needs to merge such a type.
> Wouldn't this provide a form of uniqueness typing a la Clean? In fact,
> couldn't we implement safe state threads on top of this, instead of the ST
> monad? In fact, couldn't we work within several state threads at once?

I think the answer is yes: I think this idea can replace the IO, ST and
State monads and provide a much finer-grained form of ordering, and easy

We add a new sequencing construct to Haskell, along the lines of do and
proc. I'll call it "thread", though this is probably a poor choice. It
takes a list of expressions and causes the implicit return values of each
expression except the last one to be passed as implicit parameters to the
next expression in the list. Implicit parameters not "consumed" by a
particular expression would have to become implicit return values, and I'm
not sure exactly how this should work.

The main function has a type like

  (?io :: State) => ((), ^io :: State)

The state parameter must be unforgeable. The simplest way to achieve this
is to give it a special name which the program is forbidden to mention in
binding and pattern-matching constructs.

Of course this threading carries no runtime cost, as the code generator
knows not to generate code to pass values of type State around.

Each time the user creates a ref (or mutable array), it gets its own
independent state parameter, which is automatically threaded through
future uses of the ref by "thread" constructs. Any function that uses
certain refs will include in its type an explicit list of the associated
state parameters of those refs.

This creates a problem: if each ref has its own state parameter, what are
their names? This issue came up with implicit parameters also: the fact
that implicit parameters have only names, whereas typeclasses are
parameterized by type, was a source of surprising differences between the
two. I see now that this can be solved by allowing implicit parameters and
return values to be parameterized by types as well. Thus we have

  newRef   :: a -> (exists s . Ref s a, ^st s :: State)
  readRef  :: (?st s :: State) => Ref s a -> (a, ^st s :: State)
  writeRef :: (?st s :: State) => Ref s a -> a -> ((), ^st s :: State)

(It's not clear that readRef actually needs to return the state.)

Furthermore, there should be a subclassing system for implicit values, so
that (for example) the IO monad can be split into independent pieces and
?io can be shorthand for all of them.

-- Ben

More information about the Haskell mailing list