[Haskell-cafe] Is my code too complicated?
claus.reinke at talk21.com
Sat Jul 3 09:45:59 EDT 2010
> Most languages today provide a certain "glue" to bring everything
Most languages today provide several kinds of glue and, while some
of those kinds are not recommended, Haskell unfortunately doesn't
provide all useful kinds of glue. Especially the module system is a
weak point: in SML, you'd have parameterized modules, in Java,
you'd have dependency injection (of course, being Java, they do
everything the hard way, via XML and reflection; but they are
already on their way back, with things like Spring, annotations,
and aspect-oriented programming, pushing full reflection under
the hood, permitting to compose plain-old Java objects, and
reducing the role of XML configuration files), in Haskell, we have ??
(yes, extended type-classes are equivalent to SML modules in
theory, but not in hackage practice, nor are first-class modules
modelled via extensible records).
> The problem with that approach is: This makes my code harder to
> understand for beginners. Usually they can tell /what/ my code is
> doing, because it's written in natural language as much as possible, but
> they couldn't reproduce it. And when they try to learn it, they give up
> fast, because you need quite some background for that.
What kind of beginner? What kind of background? Since you are
talking to a PHP developer, you will first have to repeat the common
parts of both languages, pointing out all the headaches that disappear
when moving from PHP to even imperative Haskell (static scoping
and IO typing means no accidental global variables or accidental
side-effects, much less manual-reading to figure out which parts
of some library API are functional, which have side-effects, etc.).
Then your friend has to start trusting the compiler (those unit
tests that only make sure that we don't break scoping disappear;
those defensively programmed runtime type checks and comment
annotations disappear in favour of real statically checked types; etc)
and libraries (much less worrying about whether some library
routine will modify its parameters in place; callbacks are no big
deal or new feature; many design patterns can actually be encoded
in libraries, rather than pre-processors; which means that small-scale
design patterns are worth a library; etc.).
Once that happens, a whole lot of thinking capacity is freed for
worrying about higher-level details, and you two will have an
easier time walking through high-level abstractions. Do not
try to lead your friends through higher-order abstractions in
Haskell when they are still worrying about small stuff like
scoping or type safety - that would be frightening.
> Also sometimes when I write Haskell, my friend sits beside me
> and watches. When he asks (as a PHP programmer with some
> C background), say, about my types, I can't give a brief explanation
> like I could in other languages.
When looking through job adverts, I get the impression that nobody
is working in plain programming languages anymore: it is Java plus
Spring plus persistence framework plus web framework plus .., and
for PHP especially, it is some framework or content-management
system that just happens to be programmed and extended in PHP,
but otherwise has its own language conventions and configuration
If you think of monad transformers and the like as mini-frameworks,
implemented *without* changing the language conventions, should
they not be easier to explain than a PHP framework or preprocessor
that comes with its own syntax/semantics?
> Yesterday I was writing a toy texture handler for OpenGL (for loading
> and selecting textures). He asked about my TextureT type. I couldn't
> explain it, because you couldn't even express such a thing in PHP or C.
> type TextureT = StateT Config
> -- Note that this is MonadLib.
> -- BaseM m IO corresponds to MonadIO m.
> selectTexture :: BaseM m IO => B.ByteString -> TextureT m ()
State monads are the ones that translate most directly to an
OOP pattern from the Smalltalk days: method chaining (each
method returns its object, so you can build chains of method
calls just as you can chain monad operations. The state is
held in the object (which is similar to holding a record in a
State monad instead of nesting State transformers, but
inheritance could be likened to nesting).
Of course, in imperative OOP languages, only programmer
discipline keeps you from modifying other objects as well,
while in Haskell, the type system sets safety boundaries
(not in the "there is something wonderful you can't do"
sense but in the "you'd hurt someone if you'd do that" sense).
> I fear that my code is already too difficult to understand for
> beginners, and it's getting worse. But then I ask myself: I've got a
> powerful language, so why shouldn't I use that power? After all I
> haven't learnt Haskell to write C code with it. And a new Haskell
> programmer doesn't read my code to learn Haskell. They first learn
> Haskell and /then/ read my code.
It is necessary to understand enough of Haskell that one gets
comfortable not thinking about less important details. After that
the adventure can begin.
That doesn't mean that any complexity is justified (watch out
for examples from "evolution of a Haskell programmer" in your
code base;-), also tool support would be great (when I first
encountered Programatica code I was frequently at a loss to
figure out which part of their monad stack some piece of code
was actually running in; figuring that out meant being
side-tracked from what one was thinking about at the time).
> Is this a real problem or am I just exaggerating?
> What do you think?
There's a real danger in there, but it need not become
a problem once you are aware of it.
Secret of Haskell programmers: you don't need to be more
intelligent to solve more complex applications, just as long as
you don't have to waste your limited intelligence on the
wrong kind of problems.
More information about the Haskell-Cafe