pozorvlak: (Default)
Saturday, June 6th, 2009 10:33 pm
I've got a problem: I've had an idea I want to write about, but it depends on two or three other ideas I wanted to write about but never got around to. So I'm going to write this post in a top-down, Wirthian fashion, stubbing out those other posts: maybe, if there's enough interest, I'll come back and write them properly and replace the stubs here with links. OK with everyone?

Right, on with the motley.

Stub post no. 1
Extreme Programming (XP), whether intentionally or unintentionally (and my money is on "intentionally, but try getting them to admit it") is really good for getting work out of people who are bright but have short attention spans. This is a Good Thing. It's most obvious in the case of pair programming - imagine saying to your partner "Y'know, this is kinda hard. Let's surf Reddit for a while" - but actually, most XP practices have this benefit. Short feedback cycles, concrete rewards, definite "next moves" (given by failing tests and the "simplest thing that could possibly work" approach) - all of these things have the effect of maintaining flow and reducing the incentive to slack off. It's programming as a highly addictive game. Dynamic languages work well with this approach, because they make it as easy as possible to get something up and running, and to test the things you've written.

Stub post no. 2
Haskell is the opposite. It encourages deep thinking, and everything about the language makes it as hard as possible to get something running unless it's just right. Screw up, and you're not presented with a running program and a failing test that you can run in the debugger; you're presented with an unfriendly compiler message and a bunch of dead code that you can't interrogate in any meaningful way. After a morning hour few minutes of this (usually involving no small loss of hair), the consultant Barbie that lives in my head invariably says "Statically-typed pure functional programming is hard. Let's go shopping!" And I, fed up and mindful of my scalp, agree. This is why I am no good at Haskell.

Stub post no. 3
Everything I read by or about the climber Dave MacLeod (blog) makes me more inspired by him. Partly for his visionary climbs, but mostly for his approach to choosing, training for and tackling really hard problems, which I think should generalise really well, if only I could put my finger on what exactly it is. It helps that he's a really friendly, pleasant guy in person. Check out the BAFTA-winning film Echo Wall that he and his wife made about his preparation for his first ascent of the trad route of the same name. If you're in Edinburgh, you can borrow my DVD, I'm positively eager to lend it out.

Anyway, something Dave wrote about training (which I can't be arsed to find right now) said that in order to train effectively, you have to be constantly pushing yourself in some way: either in terms of power, or stamina, or technique, or fear¹, or whatever. You have to find your comfort zone and then consciously go beyond it, in whichever direction you wish to improve. As you improve, your comfort zone shifts, and you need to keep pushing yourself harder and harder in order to continue to improve. But (and here's the interesting bit), he said that if you do this for long enough, your whole conception of comfort shifts, and you start to feel uncomfortable if you aren't pushing yourself in some way.

So, here's the thought I had. Maybe all the Haskellers have been training themselves Dave MacLeod-stylee, and now only feel comfortable pushing themselves really hard, and that's why they like using such a bloody difficult language.

¹ About a year and a half ago, I was seconding a route called Dives/Better Things (Hard Severe) in Wales, and got to a bit that was a bit too hard and a bit too scary. I floundered around for a bit, getting more and more freaked out, and then said to myself "What would Cale Gibbard do? He'd pause for a bit, think really hard, work out exactly what to do next, and then do that. OK. Do that, then." I have no idea if Cale climbs, but it did the trick. Cale, if you're reading, thanks for that :-)
pozorvlak: (babylon)
Monday, June 2nd, 2008 12:09 pm
Random thought: I'm sure people who actually know about this stuff will be able to tell me why it won't work, or, alternatively, cases where it's already been done.

Recall the problem with the naive Haskell mean program
mean xs = sum xs / length xs
which when asked to calculate the mean of [1 .. 1e9] allocates 8GB of RAM and brings the computer to a grinding halt. The problem there isn't really to do with naiveté: a similarly naive Ruby version works fine and runs in constant space, albeit slowly. The problem is garbage collection, or rather the lack of it. The Haskell runtime calculates the list [1.. 1e9] bit-by-bit so it can be summed, and normally would be able to throw every element away when it was done with it; but because the elements of the list will later need to be counted, there's still a (very long) pointer chain from the top-level to any given element of the list. So none of it can be garbage-collected.

In this case, this is a bad strategy: the effects of swapping out that much memory totally eliminate any benefit from caching the list. It would be quicker to throw the list away and calculate it again from scratch. Since Haskell's a purely functional language, we could in principle do this without worrying about any side-effects of the calculation. We could set up our garbage collector to become more aggressive as memory got shorter: when it starts to use swap, we could throw away any pure data that's more than N indirections from the toplevel, where N is varied dynamically to maximise performance. But what if our program is, say mean $ take 1000000000 mersennePrimes? Then it will take much longer to re-calculate the values than it would to swap them in and out of core. You'd need to keep track of how long each function call takes, and how long each bit of data took to calculate, and estimate re-calculation times when throwing data away.

But this is exactly the kind of profiling data that you need to track for the smart optimizing VMs that Steve Yegge talks about here. So, it seems that there's a synergy here. Does anyone know of a Sufficiently Smart VM that does this kind of aggressive garbage collection? Has it been tried before? Is there some obvious problem with the idea that I'm not seeing?
pozorvlak: (Default)
Friday, May 16th, 2008 12:12 pm
There was a recent mailing list post by Andrew Coppin (which received some discussion on programming.reddit) in which he bemoans the way that GHC, when presented with reasonable-looking code, can suddenly and mysteriously decide that it needs to allocate gigabytes of memory, slowing your system to a crawl for ages (I've had similar problems myself). Andrew's example was the following:

I offer up the following example:
mean xs = sum xs / length xs
Now try, say, mean [1.. 1e9], and watch GHC eat several GB of RAM. (!!)
This is not so mysterious when you remember that Haskell uses linked lists as its native list structure, and so the only way to calculate length xs is to traverse the list a second time: the runtime system "helpfully" keeps around the copy of xs that it generated while calculating sum xs, and you have a space leak. But what to do about it?

The story so far )

Doing it in Perl )

Doing it in Ruby )

Take-home messages )
pozorvlak: (polar bear)
Thursday, May 8th, 2008 02:20 pm
I know I'm very late to the LOL$thing party, but what the hell:

Cut for size )

Now, I reckon about half of you will recognise the guy in the pictures, and about half will understand the captions. I'm interested to know how large the intersection is...
pozorvlak: (gasmask)
Thursday, March 6th, 2008 11:25 am
A comparison of the Haskell argmunger with its Arc equivalent (or even its Perl equivalent) should make something clear. It's been claimed that Haskell doesn't need macros, because most of the things that Lispers need macros for can be done in Haskell using lazy evaluation and so on. But the argmunger example makes it clear that there are things for which Lispers don't need macros and Haskellers do - if not Template Haskell macros, then SYB or DRiFT or some other macro-like facility.

Lispers often say that coding in other languages feels like manually generating macroexpansions. I'm nobody's idea of a Lisp hacker, but I often feel like this when I'm writing Haskell. Which is why I'm learning about Template Haskell even though I'm not yet au fait with things like do-notation and monad transformers, which most Haskell experts would probably consider more basic. Would you choose before or after you'd walked to Moscow to staunch the blood from your severed arm?
pozorvlak: (Default)
Wednesday, March 5th, 2008 10:37 am
[The hope was that this post would come in three somewhat independent sections: one pure programming, in which we develop a small utility in Template Haskell; one largely mathematics, at the upper-level high school to beginning undergraduate level, wherein we describe another approach to constructing our utility; and one purely mathematical, more sophisticated but fairly handwavy, wherein I relate all this stuff to my research interests and describe where it leads. The idea was that you could skip the code and jump to the maths, or read the code and skip the maths, or whatever. However, just the first section has now taken far longer than I'd budgeted, both in time and in space, so I'll save the other two for a later post.]

In a recent post, Hitesh Jasani writes about Haskell's flip operator, which takes a function f and returns a function which behaves like f with the order of its first two arguments reversed. So (flip f) x y z w = f y x z w (we write function application without brackets, as is customary in Haskell). I pointed out to Hitesh that actually, we could write such a function in almost any language which supports higher-order functions, and in dynamic languages (like Perl or Lisp) we can go further, and write a function argmunge, which accepts two functions and permutes the arguments of the first one (the "victim") according to the second (the "munger"). So
(argmunge f g) x1 x2 x3 x4 ... = f xg 1 xg 2 xg 3 xg 4  ...
Here's an implementation of argmunge in Perl, and some code to exercise it:
sub argmunge {
    my $func = shift;
    my $munger = shift; # not necessarily a permutation
    return sub { $func->(@_[@$munger]); }
}

sub myprint {
    print "Called with args ".join(", ", @_)."\n";
}

argmunge(\&myprint, [2,5,5,6])->(0,1,2,3,4,5,6);
argmunge(\&myprint, [3,2,1])->("fred", "barney", "betty", "wilma");
When run, this displays
Called with args 2, 5, 5, 6
Called with args wilma, betty, barney
Here we don't pass the munger in as a function, but rather as a list of values [g(0), g(1), ..., g(n)]. I'm prouder of that code than I probably should be, because it relies on some nice Perl features to work as it does; namely, Perl's argument-passing convention (in which all arguments are passed to a function as a single array called @_), list slicing (in which you can index into a list with another list), and list flattening (in which inclusion of one list in another splices the inner list into the outer list, resulting in a flat list). I remarked that it wouldn't be possible to write a general argmunger in Haskell, because the type of the result depends crucially on the actual value of the munging function. It ought to be possible to write one in a dependently-typed language like Cayenne - anyone care to do so?

[Edit: it's possible to write an even nicer version in Arc.]

Anyway, it may not be possible in vanilla Haskell, but it is possible using templates. )

The final code can be found here. As always, all suggestions for how I could improve my code or my development practices are gratefully received!
pozorvlak: (Default)
Tuesday, March 4th, 2008 11:43 am
My post about design patterns and if-statements in Smalltalk yesterday got a very pleasing reaction, garnering some informative comments from knowledgeable people and making the front page of programming.reddit. I guess I should have checked my facts on Smalltalk semantics more carefully before clicking "Post" :-) One comment that particularly interested me was this one (sadly anonymous), which shows a rather cute trick for using Smalltalk-style keyword methods in Haskell:
data Then = Then
data Else = Else

if' :: Bool -> Then -> a -> Else -> a -> a
if' True Then t Else f = t
if' False Then t Else f = f
Now that's pretty cool, and could even be useful for DSL implementation1. But there's a problem. See the repeated code?
data Then = Then
data Else = Else
Here, let me show it to you the way it looks to me:
data Then = Then
data Else = Else
Literally half the elements that aren't pure syntax on those lines are repeated. What I'd like to do is define a keyword function, and then just write
keyword Then
keyword Else
Or, better,
keywords Then Else
Not a big deal, you might think, but what if you were writing a whole EDSL with many keywords? Or many different EDSLs? And it's not just the repetition: by defining a keywords function, I'd move the code up an abstraction level, making my intent clearer. We could of course write
data Keywords = Then | Else
but then we lose the benefit of compile-time syntax checking of our EDSL. Well, I guess our pseudo-keywords are syntactic sugar anyway, so it doesn't really matter. But still.

A few days ago, someone asked me for an example of code that's repetitive in Haskell but wouldn't be in Perl, and here's one. In Perl, and probably in Python, I could write a keywords function. It would be ugly, and would involve hairy symbol-table hacking or calls to eval, but the user wouldn't need to know that and I'd only need to write it once (never mind the fact that the "pseudo-keyworded functions" pattern wouldn't actually make any sense in Perl...). In Lisp or Ruby, I wouldn't need to write it at all, because I could use symbols instead. But perhaps this kind of thing (and other, more egregious examples) are just the price we pay for Haskell's type system, and are more than balanced out by greater opportunities for concision and abstraction elsewhere?

Nah, bollocks to that. We can do better.

Template Haskell to the rescue! )

The final version of Main.hs is here, and the final version of Keyword.hs is here. Not entirely straightforward, but we pretty much got there in the end. Would it be worth posting these code samples to the TH wiki, and perhaps linking here? Anyway, it's nice to have finally got this simple stuff to work: hopefully I'll be able to get some more difficult things to work soon, and this should reduce the amount of frustration and needlessly duplicated code in my Haskell programming experience.

1 Did you know you can do this in (plain) TeX, too?
\def\fred #1 barney #2 betty{#1#2}

\fred Hello there, barney Wilma betty !
produces "Hello there, Wilma!".
pozorvlak: (Default)
Saturday, February 23rd, 2008 10:47 pm
I observe to my astonishment that I've made the "Quotes of the Week" section of this week's Haskell Weekly News. Um, gosh.

Now if only I could work out if I've been quoted because dons agrees with me or wishes to hold me up to public ridicule :-)
pozorvlak: (polar bear)
Tuesday, February 12th, 2008 10:26 am
I'm going to make what should be an uncontroversial statement: if you don't understand and use monads, you are at best a quarter of a Haskell programmer. A corollary of this is that, since using monad transformers is the only (or at least the approved) way to use two or more monads together, if you don't understand and use monad transformers you are at best half a Haskell programmer.

[Another corollary is that I am, at best, about an eighth of a Haskell programmer: though I understand monads well on a theoretical level, I invariably emerge defeated from any attempt to bend them to my will.]

But we'll come back to that later.

Something I've been thinking about for a while is this whole business of designing languages to make programs shorter. )

1 There really ought to be a word that means "would never use a twopenny word when a half-crown word would do", but I can't think of one. English grads? Edit: sesquipedalian! Of course! Thanks, [livejournal.com profile] fanf! (Originally, I used "prolix")
2 I actually came up with this list by thinking about languages whose users were the most passionate. But they're also extremely concise, which I think is a large part of the reason for the passion. If I were focusing purely on concision, I should probably consider Forth, but I don't know enough about it.
3 J has "boxed arrays" too, which are something like two-dimensional s-expressions, but let's leave those aside for now.
4 You might want to raise this objection against Smalltalk, too: objects are members of classes, which are something like types. Now, I've hardly used Smalltalk, so I'm probably talking out of my elbow, but: since everything is an object, and the language has powerful reflection features and duck typing, we can in fact write generic operators that work for objects of many or all classes. But maybe I'm entirely wrong about Smalltalk programming: in which case, please delete all references to the language from my argument.
5 Do you find yourself wanting to go out and strangle small fluffy animals every time you have to type out an instance declaration that would be entirely unnecessary in a duck-typed language? I do. Particularly when it doesn't work and spits out some ludicrous error message at me, telling me that I've encountered another stupid corner case of the typeclass system.
6 I learned to my surprise the other day that I'm a member of the Geometry and Topology research group, and not the algebra research group as I'd always assumed - apparently universal algebra is now considered a branch of geometry!
pozorvlak: (gasmask)
Tuesday, February 5th, 2008 02:35 am
[livejournal.com profile] totherme kindly drew my attention to this blog post today. The author, Slava Akhmechet, tries to explain away that horrible feeling of unproductivity and frustration that I know so well from my attempts to use Haskell: his claim is that it's just that my expectations are miscalibrated from using imperative languages. A Haskell solution to a given problem, he claims, will take the same amount of thought as a solution in another language, but much less typing: by simple statistics, therefore, you're going to spend a lot of time staring at the screen not doing anything visible, and this can feel very unproductive if you're not used to it.

As an example, he gives the code
extractWidgets :: (Data a) => a -> [String]
extractWidgets = nub . map (\(HsIdent a)->a) . listify isWidget
    where isWidget (HsIdent actionName)
              | "Widget" `isSuffixOf` actionName = True
          isWidget _ = False
Bleh! :-( This function takes a parse tree representing some Haskell code, and extracts all the identifiers ending in "Widget", then removes the duplicates. Slava challenges any Java programmers reading to do the same in five lines or fewer.

Pointless language pissing match, including some Arc coding )

On language concision in general: I typically find that Haskell requires fewer lines for a given program, but Perl requires fewer characters, and they both use about the same number of tokens. Lisp is longer and messier than Haskell for easy problems, but quickly gains ground as the problems get harder.1 The APL family own on all three axes. This is extremely unscientific, of course, and because I don't know much APL/J I can't be sure how it extends to harder problems. I did once email Paul Graham asking why, if succinctness was power, he didn't switch to a member of the APL family; he has yet to reply, but I don't attach any great significance to this.

And having got all that stuff out of my head, I'm going back to bed. Hopefully I'll be able to sleep this time :-)

1Fun exercise: translate the example code in On Lisp into Haskell (or Perl, Ruby, etc.). It really helps you to get to grips with the material in the book. I found that the Haskell solutions were shorter and cleaner than the Lisp solutions up until about a third of the way through the book, at which point Lisp started to catch up with a vengeance: shortly thereafter, he was doing things in a few lines of Lisp that simply couldn't be done in finitely many lines of Haskell. I'd be very interested to see solutions written by someone who knew what they were doing, though!
pozorvlak: (gasmask)
Wednesday, January 23rd, 2008 04:11 pm
Bloody Haskell: it's like a scab I can't stop picking at.

Prompted by something on Reddit, I started thinking about libraries to pluralize (English) words, like the table-name generator in Ruby on Rails or Damian Conway's (rather more complete-looking) Lingua::EN::Inflect for Perl. Such things seem to be called "inflectors". My question is, what would be the idiomatic interface for a Haskell inflector? The obvious thing would be something like
    pluralize :: Inflector -> String -> String
where Inflector is some sort of data structure holding configuration data: classical versus modern plurals, any custom cases, etc. But following on from our earlier discussion of high- and low-level type-checking, it occurred to me that there's a constraint here: only singular nouns should be pluralized. So should we then have
    newtype Singular = String
    newtype Plural = String

    pluralize :: Inflector -> Singular -> Plural
? Or even
module Inflect (makeSingular, pluralize)
    data Singular = Singular String
    data Plural = Plural String

    makeSingular :: String -> Singular
    -- error-checking code goes here, to check that the string passed
    -- is a single word, or something

    pluralize :: Inflector -> Singular -> Plural
so we don't export the constructors for Singular or Plural, ensuring that one can only construct them using our interface? But wouldn't this make client code far uglier than necessary? Should one then provide both options, tagging one as unsafe?
    module Inflect (makeSingular, pluralize, unsafePluralize)
    data Singular = Singular String
    data Plural = Plural String

    makeSingular :: String -> Singular
    -- error-checking code goes here

    unsafePluralize ::Inflector -> String -> String

    pluralize :: Inflector -> Singular -> Plural
    pluralize i (Singular s) = Plural (unsafePluralize i s)
Thoughts?
pozorvlak: (polar bear)
Thursday, January 17th, 2008 02:54 pm
Here's something I've been wondering about for ages. When I'm programming, I find worrying about the types of variables to be generally unhelpful, and being forced to think about such things by the compiler is downright irritating. Yet when I'm doing mathematics, I think type-centrically all the time. The two activities are strongly connected in my mind, so it's surprising to me that there's this difference.

Here are some theories I've been kicking around )

By the way, remember a while ago when I was musing on the possibility of static duck-typed languages? Well, it seems that Scala is one :-)
pozorvlak: (Default)
Monday, January 7th, 2008 10:33 pm
This afternoon I gratefully took possession of the copy of Iverson's A Programming Language which the library had been holding for me. Within two sentences, he'd managed to say something so thought-provoking that I felt compelled to post about it here. )
pozorvlak: (Default)
Friday, December 28th, 2007 11:45 am
I got the job application in, finally: here's the revised (or rather, totally re-written) research proposal, and here's the summary for laymen. You will notice the point where I thought "Speculative? Ha! I'll show you speculative!" I'd really appreciate feedback, especially on the one-page summary: the two or three formulae in there should be helpful to some, but can safely be ignored if they make your eyes glaze over. The proposal got mailed off at about 5am on Wednesday morning: I then went to bed for a couple of hours before getting up to catch the bus down to Sheffield at 9.15. We missed the bus, but we were only round the block from the railway station, so we caught the train as far as Edinburgh and joined our bus there. The train journey gave me time to write most of the one-page summary: just as well, really, as I found it impossible to type on the bus.

Panto! )

Monads! )

Then [livejournal.com profile] wormwood_pearl and I got on our respective trains, she back to Glasgow and I on to Oxford, to see our respective families for Christmas. Christmas chez Vlak has been pretty good, though marred by the need to put up endless amounts of flat-pack furniture: my Dad is building a new workshop, and needs cupboards and drawers and so on to put his stuff in. Now, I'm no great craftsman, but I'm not a complete incompetent: but these units have been a total nightmare. The instructions are unclear and barely-legible, everything's bizarrely sized so measurement is that little bit harder (the door handles are 12.8 cm from centre-hole to centre-hole - or 5 and a sixteenth inches, if you prefer), I'm 99% certain they've replaced a small but crucial bit with a new design that invalidates the bundled instructions, and no matter how paranoid I am, no matter how careful I am to measure everything three times and clamp everything as tightly as I can and drill everything as straight as I can, nothing ever fits right the first time. A single drawer unit took us nearly three hours to assemble the other day.

Other than that, Christmas has been pretty good. It's always nice to see my family, and I managed to meet up with [livejournal.com profile] mrkgnao and [livejournal.com profile] necaris the other day. My last-minute Christmas presents to the parents* seem to have been appreciated (as were theirs to me - yay for books, head-torches and Hustle on DVD!). And now [livejournal.com profile] wormwood_pearl has arrived down South, so we can spend New Year together :-)

In entirely unrelated, but sad news, Oscar Peterson, arguably the greatest jazz pianist of all time - screw that, arguably the greatest pianist of any kind of all time - died a few days ago, at the age of 82. If you don't know his work, you really owe it to yourself to check it out. Start with his recording of Porgy and Bess, which completely transformed my understanding of the piece, but frankly it's all good.

* Literally last-minute: they were about to close Blackwell's on Christmas Eve as I bought them. Fortunately, they were also marking everything down to half-price rather than £2 or £3 off :-)
pozorvlak: (Default)
Wednesday, December 19th, 2007 08:14 pm
An email from the people to whom I applied:
I missed the point entirely, it seems :-( )
I wouldn't mind so much if they'd asked for a "Personal Statement" or something - to me, the term "Research Proposal" suggests that it should mainly be about the research that you propose to undertake. But apparently not. I've got until, er, tomorrow to submit another one :-(

In other news, hearken ye programmers unto Steve Yegge's latest drunken blog rant. I've been having similar thoughts myself, related to Bad Things that have happened to me with big codebases: it's a large part of why I'm so interested in the APL family*. But I'd like to stick my neck out and say that the way Steve feels about Java is the way I feel about Haskell.

* I note in passing that that page comes up first in a Google search for "APL lesson" - epic win!
pozorvlak: (babylon)
Tuesday, October 16th, 2007 01:31 pm
A really cool result, that I became aware of via John Baez's This Week's Finds column:

Though the Haskell community make efforts to conceal this fact from you, monads are not tied to any particular category (whether it's Hask or Set). We can consider monads on any category C: more generally than that, we can consider monads in any 2-category! Simply take the laws that define monads, express them as pasting diagrams, and voilà: your definition works in any 2-category. The monads that we started with are now just this new kind of monad, interpreted in the 2-category Cat. This kind of trick can be done with many categorical constructions: we can talk about adjunctions in an arbitrary 2-category, for instance.

OK, so far so standard. But here's where it starts to get cool: the collection of monads in any 2-category C forms a 2-category itself! Call this 2-category Mnd(C). Since Mnd(C) is a 2-category, we can ask about the monads in it, and consider Mnd(Mnd(C)). The first cool result (due to Street, back in 1972), is that an object of Mnd(Mnd(C)) (i.e., a monad in the 2-category of monads on C) is a pair of monads T1, T2 in C related by a distributive law - a distributive law being precisely the data needed to make the composite T1.T2 into a monad!

[BTW: if anyone can explain the relationship (if any) between distributive laws and monad transformers, I'll be extremely grateful...]

Can you guess the second cool result?

I won't keep you in suspense. The second cool result (due to Cheng, and very recent), is that a monad in Mnd(Mnd(C)) (i.e. an object in Mnd(Mnd(Mnd(C)))) is three monads T1, T2, T3 in C, together with the extra data needed to make the composite T1.T2.T3 into a monad!

OK, now I need to read her paper...
pozorvlak: (babylon)
Tuesday, October 2nd, 2007 11:24 pm
Another one for the "using computers to investigate trivial mathematics" file...

I had another meeting with my STEP student today, who showed me the following problem: find a simple expression for the sum of the squares of the nth and (n-1)st Fibonacci numbers. In other words, what is Fn2 + Fn-12? We're taking the zeroth Fibonacci number to be 0, and the first to be 1.

My conjectured answer, and some supporting evidence )

I still can't see a proof, but no doubt one will occur to me in the morning...

In other news, I've been playing around a bit more with the Catalan numbers - in fact, I briefly thought they might have something to do with my actual research, and got very excited, but on further reflection I don't think they're very helpful. But it seems likely that the reason the "naive" J code hung didn't have all that much to do with the naiveté of the algorithm - using the same algorithm, and on the same machine, MIT Scheme (interpreted) was able to calculate the 100,000th Catalan number in around 100s, with no paging or machine-locking, and Python was able to calculate it in under 20s! It seems to me that J is using either a poor bignum implementation, or (more likely) a very poor implementation of the binomial coefficients - I discussed this with my father (we're that kind of family), and he suggested that it's probably written recursively, and thus consumes vast amounts of stack space. Easy enough to fix, if only the J interpreter weren't closed-source...
pozorvlak: (gasmask)
Monday, October 1st, 2007 09:18 pm
Implementation-defined languages come in for a lot of flak. Users of certain languages will point to their language's standards document as if it were self-evidently proof of greater inherent worth: a language that's defined by its implementation, it is implied, is always going to be a bit non-U. It may train itself out of its dropped H's and tendency to mispronounce the word "scone"1, but it will never have the true breeding that comes from a standards document.

Which is daft, because implementation-defined languages have some important advantages )

By the way, I'm not saying that all specifications are bad (a good one is an excellent thing to have) or that specification-defined languages have no advantages - I'm assuming that the advantages of specification-defined languages are so well-rehearsed that I don't need to repeat them. Anyone needing further enlightenment is encouraged to go to comp.lang.scheme and say "I think spec-defined languages suck!" :-)

Now for the second part of my rant: Haskell, as we know it today, is an implementation-defined language, defined by the latest CVS snapshot of GHC. "But what about the Haskell Report, and the Revised Report, and Haskell prime, and Hugs, and, er, those other implementations?" I hear you cry. Well, what about them? Every time I asked some question, it seemed, the answer would begin with "first download the latest version of GHC, then turn on these extensions..." A spec for a language that people don't actually use is - well, not useless, if it's sufficiently close to a language that they do use, but it ain't a specification as I understand the term. Everyone in the Haskell community seems to track the latest version of GHC for its new features. This is not spec-like behaviour. Now, as I said above, I don't think that implementation-defined languages are bad: quite the reverse. I just think it would save everyone a lot of bother and false superiority if the community could admit this to itself and to outsiders.

1 The O is short: "scone" rhymes with "gone", not "groan". Unless you're talking about the town in Scotland, when it rhymes with "boon". People who insist on mispronouncing this word around me will have their scones taken away from them and donated to the Pozorvlak Pedant-Feeding Drive.
pozorvlak: (Default)
Wednesday, September 12th, 2007 09:25 am
Short version: I'm going to write a mildly cool and somewhat useful utility in Ruby which shows off Ruby's reflection capabilities and has something to do with my PhD thesis.

OK, first some (not really necessary) mathematical background )

OK, that's the maths out of the way, on to the code. The ability to do categorical composition of functions is useful, so maybe the multicategorical kind would be useful too? Ideally, we'd like a compose function which took a function f and a list of functions g1, g2, ... gn, and returned the function f.(g1,...gn) which takes (x11, ... xnmn) to
f(g1(x11 ... x1m1) ... g1(xn1 ... xnmn))
Unpleasant multiple sequences seem to be an unfortunate fact of life when dealing with this stuff. Anyway, here's an implementation in Ruby )

I'm sure this code can be improved, and I'd love to hear how. I don't think it's possible to write a function like this in vanilla Haskell, and writing one in Template Haskell is beyond my template-fu. It would be possible in Perl, but because of Perl's eccentric argument-passing conventions, you'd have to manually pass the arities in. This also uglifies the code somewhat.
pozorvlak: (Default)
Monday, September 10th, 2007 12:39 pm
Current status on some of my long-term projects:

Thesis: Up to 36 pages )

Birdshot!: I had some good ideas for this )

Moving in with [livejournal.com profile] wormwood_pearl: Nominally moved in at the beginning of August. )

Learning Haskell: I'm going to officially give up on this one for now. )

Diet: This is going really well. )

Munro-bagging: up to 61 out of 284 )

Becoming a l33t martial artist: I've been doing some capoeira. )

Learning to juggle 5 balls: I'm getting 8 catches pretty consistently. )

Reading Ulysses: Haven't looked at it since I reached page 500. ) I seem to have so many other things competing for my attention :-)