
Most languages today provide a certain "glue" to bring everything together.
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 languages. 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. Claus -- 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.