[Haskell-cafe] Re: nested maybes

J. Garrett Morris trevion at gmail.com
Wed Feb 7 00:16:04 EST 2007


On 2/6/07, Yitzchak Gale <gale at sefer.org> wrote:
> J. Garrett Morris wrote:
> Well, no, but it is at least no worse than
>
> apply :: Handle -> Attribute a ->
>   ContT (StateT Blargh (ErrorT Fzzt IO)) a
>
> I find that in general, many functions do
> not need all of the capabilities. If they do,
> you can alias that also:

Well, in this case, the function looked more like:

apply :: Handle -> Attribute a -> S a

Part of the point here was that S was an abstraction.  Most functions
weren't accessing the state or the continuations directly - and their
interaction with the error type had an intermediary as well.  Instead,
they were using operations that, in turn, used the underlying pieces.

> You often need to make changes to the monad stack -
> add or remove capabilities, reorder, etc. This way,
> you only change the type in one place, and only
> fix functions that use the particular capabilities that
> were changed.

This is the same with my newtype-deriving alias.

> The usual advantages of polymorphism apply -
> gives separation of concerns, encourages reuse,
> eases maintenance and testing, better expresses
> the meaning of the function by not mentioning
> unneeded details.

Well, we accomplished this all by having an abstraction barrier
between a set of basic operations (which knew, at some level, about
the internals of S and had their own sets of unit tests) and things
built on top of S (which hypothetically could have gotten to its
internals, but didn't.  It would have been better practice to not
export the instances, but I didn't think of that at the time_.

> By the way, are you really doing CPS? If you are
> only using ContT to get short-circuiting, you could
> probably also simplify things by using ExitT
> instead:

We had a threading system which scheduled application threads to a
limited number of IO threads based on data-driven changing priorities.
 This was first designed for GHC 6.2.2, when the threaded runtime
wasn't in the shipping versions yet.

I really think we're just talking about two approaches to the same
thing.  I prefer to encapsulate most of the MonadX operations as soon
as possible behind a domain-specific layer, and then write the rest of
my code in terms of that.  In that case, I get isolation of concerns
and testing and such from the fact that the internals of the monad
stack aren't exposed, and if they need to be changed it only affects
the DSL components, not the majority of the code.

 /g

-- 
It is myself I have never met, whose face is pasted on the underside of my mind.


More information about the Haskell-Cafe mailing list