Not sure if this is of interest. Just updated
blogpost app to deal with LJ cuts and usernames/communities.
If you write
<!-- "Click here for more..." -->
it gets converted into
<lj-cut text="Click here for more..." />
Also, if you do a local preview it would previously leave any user tags unchanged. But most browsers would skip over
<lj user="brokenhut" /> as an unknown tag, so you’d end up with a gap in the sentence. So I converted it into a brokenhut.
- Browse repository
- Fetch code:
darcs get --partial http://22.214.171.124/code/blogpost/
I recently got my lazy self in gear and finished a piece of code that had been languishing for a while. It had been neglected because I no longer actually needed it; and it wasn’t desperate, because there were other ways to solve the problem — ways that didn’t involve me engaging my brain.
But for one reason or another I felt it needed done. And I’m glad it’s finished, because there were a couple of interesting lessons learned.
If you want to know how to do text processing from Haskell with external programs like Markdown, then read on. It took me a while to get this working properly, with many a deadlock or zombie process along the way. So I thought it worthwhile to write up the stuff that I learned.
(I couldn’t find this information via Google. I got some useful stuff from reading the source for the Hugs interpreter and some utility libaries from John Goerzen. But trying to guess the full behaviour from reading isolated functions is a tricky business sometimes.)
( Read more...Collapse )
This is the first official pre-release announcement of JoinCabal.
It works like this:
and creates this:
The important part is the dot-cabal file, since this is quite intricate and a bit dull to set up. It just outlines the basics of the program, what the executable will be called, who the maintainer is and their contact details, that kind of thing.
A previous version called
mkcabal was written by Don Stewart. His is naturally more elegant than mine. JoinCabal — apart from being an obvious instance of NIH syndrome also writes a bit of licence header into the top of your main source file. Which is my justification for writing it.
And obviously it’s going to be grand and wonderful in the future. Obviously.
Does anyone else have this problem? You get yourself into a programming groove and all is going swimmingly, and then suddenly think of some other project you could do as well. And the other project always seems tantalisingly trivial. “I’ll just devote a bit of time to it then I’ll come back to what I’m doing.” Naturally you never come back because — if you finish the distraction — you come up with something else new to do.
It’s quite infuriating. In this case, I was going to make an app for drawing import dependency diagrams for Haskell programs. I think it should be fairly easy.
At the top level I need to store a list of modules which have been processed and whatever still to go. A straighforward depth-first wouldn’t work because modules can be appear in several places. But for each file it seems to be a case of:
- Process Haskell code with GHC to delit it. Not relevant for most people but most of my code is literal.
- Drop all lines that don’t begin with
- Drop all hierarchical modules. I’ll just deal with flat modules at the moment; I can just strip off everything with a full stop in the name.
- Emit a directed-graph description of the form
moduleA -> moduleB.
If I do all of that for each source file and wrap all the contents in the appropriate file format for graphviz, it should be fairly easy to create some nice graph pictures.
On further investigation it appears that the Function Graph Library (FGL) includes bindings for Graphviz. I think this task may have actually tipped over into the annoyingly trivial. But that’s okay, cos we’ve already established that if I did it I would just distract myself from other (already started) projects.
Another look at the documentation for the Glorious Haskell Compiler reveals that it should be easy to create a list of user-defined modules, using:
ghc -M Main.lhs
-M flag makes it spit out a makefile-style dependency list. This is even simpler to splice up and pull out the relevant data, since all the delitting and import command isolation work has been done.
It’s nice when all the work is done for you, isn’t it? We’re sliding steadily towards “temptingly easy” now. I better watch myself…
Optimus Prime may have been the greatest Transformer, but that’s not what I’m talking ‘bout here. I mean monadic transformers. And having spent some time reading about them and thinking about my next move in the Haskell programming… this is it.
What are monadic transformers? Well, most (let’s be fair: all) Haskell programs will make use of the
IO monad to deal with the outside world. However there’s a number of other instances where monads can be useful — capturing errors, logging progress, maintaining internal state.
There exist separate monads in Standard Library for this stuff:
State, for example. But joining them together can be awkward even though many programs will have use for several of them at once.
One technique would be to build your own über-monad with all the bells and whistles you want. This would be both (a) daft, as the work is already done and (b) too error-prone.
The other technique is with monad transformers. They essentially provide an automated way to do monad nesting — such as
IO (Either [String] [Bool]) — without all the tedious threading of monads. Kind of like a meta-monad, if you will, since you can sequence monads together in the way that monads allow you to sequence functions.
The other nice thing is that it cuts down on those horrible parentheses. Monad actions from different monads can be called back to back without causing a fuss. Example:
f = do a <- get -- from State monad
liftIO $ print a -- from IO monad
tell $ "found a " ++ show a -- from Writer monad
case a `mod` 2 of
0 -> throwError "even number" -- from Error monad
1 -> put $ a+2
I didn’t really understand them until I read the recent paper by Martin Grabmüller, Monad Transformers Step by Step. It’s still in draft at the moment but it’s very readable and dead useful.
I have filed this post in the category called ‘geek’ for a very good reason. For (Haskell) functional programmers and fans of Iain M Banks, well, you’ll love it. The rest of you may be a bit confused but you can read it anyway for its silly comparison at the end.
You can find a proper explanation of the IO monad elsewhere. I won’t bore you with it here. Instead let’s talk about analogies.
The basic idea is this: monads are a container or context for carrying out some operations. The
IO monad, for example, passes around an entity which we know as the Real World™. It enables pure functional languages to work properly as programming languages with input and output, without getting all mixed up. There are also other monads used besides
IO, for processes that may not return a result (
Maybe) or can return one of two different types (
Either). And there is a whole separate universe in which all these different realities — these monads — operate independently of each other.
Really, the proper way to think about the IO monad is a smaller part of the whole. Instead we are used to thinking about the real world being everything there is, and changing our analogies to suit.
And what was that about Iain M Banks? Oh yeah. Well the Minds in his Culture novels work in pretty much the same way: the justification being that only a tiny proportion of their computational power and processes exist in the real world. The two or three metre long pods which represent these AIs in the books are just tiny protrusions into our world of vastly more sophisticated beings. If you’re not a fan of Iain M Banks, Douglas Adams talks about the very same thing with his mice — “three-dimensional representations of hyper-intelligent pan-dimensional beings” or something like that.
Most discussions of monads look at them as the functional programming world’s way of accessing the wider world. I prefer to think of them the other way round, as little sandboxes where functional programming is constrained by the real world.
Either way, the result is the same but sometimes changing the perspective you look at things can open up new insights. See, for example, the selfish gene and analysis of evolutionary theory from a genetic instead of an organism level.
This won’t be of much interest to many folk, but four of the original designers of the Haskell programming language are currently writing a paper on the history of the language. Drafts are available to read on the Haskell website, but for those less motivated I thought I would highlight the important section — how they chose the name:
[A] small but important moment in any language’s evolution is the moment it is named. At the Yale meeting we used the following process (suggested by Wadler) for choosing the name. Anyone could propose one or more names for the language, which were all written on a blackboard. At the end of this process, the following names appeared: Semla, Haskell, Vivaldi, Mozart, CFL (Common Functional Language), Funl 88, Semlor, Candle (Common Applicative Notation for Denoting Lambda Expressions), Fun, David, Nice, Light, ML Nouveau (or Miranda Nouveau, or LML Nouveau, or …), Mirabelle, Concord, LL, Slim, Meet, Leval, Curry, Frege, Peano, Ease, Portland, and Haskell B Curry. After considerable discussion about the various names, each person was then free to cross out a name that he disliked. When we were done, there was one name left.
That name was “Curry,” in honour of the mathematician and logician Haskell B. Curry, whose work had led, variously and indirectly, to our presence in that room. That night, two of us realised that we would be left with a lot of curry puns (aside from the spice, and the thought of currying favour, the one that truly horrified us was Tim Curry — TIM was Jon Fairbairn’s abstract machine, and Tim Curry was famous for playing the lead in the Rocky Horror Picture Show). So the next day, after some further discussion, we settled on “Haskell” as the name for the new language. Only later did we realise that this was too easily confused with Pascal or Hassle!