[Haskell-cafe] Re: monad subexpressions

apfelmus apfelmus at quantentunnel.de
Fri Aug 3 16:22:53 EDT 2007


Chris Smith wrote:
> I'm primarily interested in the two cases where one simply has no
> choice about the use of monads: and those are IO and STM.
> No, this is not purely functional programming then; but it has
> some very compelling  advantages to Haskell's implementation of
> these, that I'm afraid are  currently quite hidden behind the
> difficult syntax.  Using something besides a monad is simply not
> an option.
>
> "The more tiresome monads are, the more incentive you have to
> avoid them."  Unfortunately, I'm afraid this cheapens work people
> are doing in making the necessary imperative parts of Haskell
> more useful and interesting.  Making monads distasteful is not a
> reasonable goal.
>
> Can you think of a single widely used programming language
> that forces programmers to write linear one-line-per-operation code
> like this?  IMO, Haskell gets away with this because STM and IO stuff
> isn't very common; and STM and IO will remain uncommon (and will
> instead be  replaced by unsafe code written in Python or Ruby) as
> long as this is the case.

I mean it in the following way: the power of Haskell is that a large
core of pure functions does the actual algorithmic work and is
surrounded by a small layer of imperative code. It's not possible to
avoid the small layer of imperative code, of course. But the more you
treat imperative code as somewhat pure, the greater the danger that the
purely functional logic will be buried inside a mess of imperative code.
In other words, the goal is exactly to make IO and STM uncommon,
otherwise you loose the power the purely functional approach offers.

What I want to say is: if you feel the urge to use the monad splicing
syntax, then I think that there's a big chance that the code you write
is in essence pure and can also be made completely pure. That's why I'd
like to see the code that made you give up. It may require much more
pondering to find a pure abstraction to the programming problem at hand.
But once found, it bests any ad-hoc code.

For example, take the HGL (Haskell Graphics Library) which actually
shows the boundary between pure and monad. The main abstraction is the type

  Graphic

that represents a graphic to be drawn on the screen. It's implemented
with a monad  Draw a  with in turns does IO to draw itself on the
screen. But the abstraction is to treat this as a purely functional
value with operations like

  emptyGraphic :: Graphic
  polygon      :: [Point] -> Graphic
  overGraphic  :: Graphic -> Graphic -> Graphic

to create and compose graphics. To draw a graphic, you have to use IO.
But his is no reason not to offer a pure abstraction even if the
internals are littered with IO.
HGL still exports the  Draw  monad

  type Graphic = Draw ()

and I consider this a sin. It only appears as monad in the three functions

  selectBrush :: Brush -> Draw Brush
  selectPen   :: Pen   -> Draw Pen
  selectFont  :: Font  -> Draw Font

which exist to enable the user to hand-optimize a bit since brush, font
and pen creation is expensive on Win32. But arguably, these
optimizations can be performed automatically under the hood.

An interesting example of how a purely functional data structure makes
life much easier is described in

  N. Ramsey and J. Dias.
  An Applicative Control-Flow Graph Based on Huet's Zipper
  http://www.eecs.harvard.edu/~nr/pubs/zipcfg-abstract.html

<abstract>We are using ML to build a compiler that does low-level
optimization. To support optimizations in classic imperative style, we
built a control-flow graph using mutable pointers and other mutable
state in the nodes. This decision proved unfortunate: the mutable flow
graph was big and complex, and it led to many bugs. We have replaced it
by a smaller, simpler, applicative flow graph based on Huet's (1997)
zipper. The new flow graph is a success; this paper presents its design
and shows how it leads to a gratifyingly simple implementation of the
dataflow framework developed by Lerner, Grove, and Chambers
(2002).</abstract>



That being said, it is of course desirable to be able to describe
genuinely imperative behavior like resource (de-)allocation elegantly in
Haskell. Not everything can be pure :) (or rather :( ). But I'm not sure
whether the linearization imposed is really an issue then.



> Ultimately, it may just have to come down to implementing the
> extension, making it available as an extension to GHC and perhaps
> other Haskell compilers.
>
> As it  stands, though, I'm just not sure how to evaluate ideas
> without language changes against an alternative that doesn't exist.

Hm, it seems slightly unfair to me to leave the burden of searching for
an alternative to somebody else.

> I can explain desugaring rules for this idea in a short paragraph.
> The alternatives all seem to involve operators and functions that I've
> not used in about six months or more of moderate playing around with
> Haskell.

In fact, applicative functors are a very useful and powerful abstraction
and to some extend, they exactly solve the problem of programming with
monads in an applicative style. I would be sad if you'd ignore them in
case they solve your STM-code problem without compiler extension.

Regards,
apfelmus



More information about the Haskell-Cafe mailing list