Undone – sci-fi comedy on BBC radio

Just a quick post about this cute scifi-ish radio show, Ben Moor’s Undone. Someone pointed me at it a couple of years ago, noting that the protagonist Edna Turner reminded him of the lovely Sally Sparrow from Blink. I loved the wordplay, the surreal alternate reality (for example, “Los muchachos que necesitan la insulina, Mexico City’s top diabetic mariachi band”), and the choice of music. And now I discover there was a 2nd series, and even a 3rd which will be broadcast in November.

Though I like the offbeat parallel reality more when it’s low key (the series finales are more high-fantasy end-of-the-world stuff) the story arc is shaping up quite interestingly, as the whole premise of the scenario is put into question (hopefully this won’t affect the surreal punning).

You can catch up on iPlayer — though, bizarrely, they haven’t stacked previous episodes, so you’d only catch the series 1 ending now, bad BBC! And while I’m knocking Auntie, why don’t the microsite or the iPlayer programme information give any details on the music used? The manic choral theme is fantastic, and the incidental music is also excellent. Any clues?

Beans pt2: docs, tests, and more types

A couple of comments on the first post suggested that I look
into the command-line bookkeeping application ledger, or
indeed, its Haskell version hledger. They look very
interesting, but rather hard to wrap my head around. So though I’m going to
bear them in mind for later, I’ll carry on doing these sketches till I
understand the problem space better, at which point, perhaps I’ll either a)
steal some ideas from them, or b) realise they are undoubtedly the way forward
and start using them.

I used Module::Starter to retrospectively turn this project
into something I can release as a distribution to CPAN, with docs, tests, a
Makefile, and so on.

module-starter --module=Beans --mi --author=osfameron --email=osfameron@cpan.org

This also creates some skeleton docs, so I’ve gone in to add a few actual
notes (mainly just pointing at this blog), and to delete a few sections that
module-starter puts in by default:

AnnoCPAN
(I don’t think this is particularly useful, and don’t see the need to
advertise it from my module, as it’s already linked to from search.cpan.org)
CPANratings
This is useful, but again, it’s already linked to from
search.cpan.org. Why should I link to it from my module? Should I also include
buttons to pimp it on reddit and digg?

Then I added some tests in t/01-basic.t, for example:

my $item = Beans::Item->new(
    name     => 'Mortgage',
    value    => 500.00,
    due_date => '2009-10-01',
    comment  => 'Home sweet home',
    tags     => [qw/ mortgage foo bar /],
    );

ok $item, 'Object created successfully';

is $item->name,  'Mortgage',      'Name ok';
is $item->value, 500,             'Value ok';
is $item->due_date->month, 10,    'Date ok';

All very noddy stuff, but it helped me find a bug in the version I’d blogged
earlier! I hadn’t told the date fields to use the coercion I’d set, so
the above code failed, complaining quite rightly that ’2009-10-01′ isn’t a
DateTime object!

So I amended the date fields like so:

     has due_date  => ( isa      => DateTime,
                        is       => 'rw',
                        required => 1,
                        coerce   => 1,
                      );

and all was again well. Yay for failing tests!
This brings me to a suggestion from John Napiorkowski to use MooseX::Types::DateTimeX to get my coercion
for free. This does indeed work, and I’ve changed the code to use it, though
it doesn’t by default use DateTime::Format::Natural — we’ll come back to
this later.

While we’re looking at types, let’s fix the crufty implementation of tags.
We’ve currently got an ArrayRef[NonEmptyStr], but really, we don’t want
an Array, because we want to be able to:

  • Check whether a given tag is active
  • Enable a tag (without duplicating it if it’s already present)
  • Delete a tag.

These aren’t so much features of arrays as of hashes, or, even better,
sets. I was about to enter a rabbit hole of implementing using a hash
and ::Meta::Attribute::Native::Trait:: when Stevan suggested
Set::Object and its wrapper
MooseX::Types::Set::Object.

This changes our code to:

    has tags      => (
                       isa      => 'Set::Object',
                       is       => 'rw',
                       accessor => '_tags',
                       coerce   => 1, # also accept array refs
                       handles => {
                           tags       => 'members', # random order
                           add_tag    => 'insert',
                           remove_tag => 'remove',
                           has_tag    => 'member'
                         },
                     );

which we can test like so:

is_deeply [ sort $item->tags],
    [qw/ bar foo mortgage /],     'Tags ok'
        or diag Dumper($item->tags);

ok $item->has_tag('foo'),         'Has tag foo';
ok $item->has_tag('bar'),         'Has tag bar';
ok $item->has_tag('mortgage'),    'Has tag mortgage';
ok ! $item->has_tag('baz'),       'Nonexistant tag baz';
$item->add_tag('baz');
ok $item->has_tag('baz'),         'Now has baz';
$item->remove_tag('foo');
ok ! $item->has_tag('foo'),       'Now lost tag foo';

Set::Object’s members function returns the contents in hashed order
(i.e., effectively random), but given that we know our “objects” are actually
strings, I’d prefer them in sorted order, which would simplify the is_deeply
test above. We could do this as a method instead, or possibly use
around to sort the results, but we’ll come back to this soon!

Coin Tricks

Derren Brown recently claimed he would predict the UK lottery numbers, live on television, and then explain how he did it. It’s doubtful that he did either — the alternative explanation that he’d actually committed a massive and improbably daring fraud is vastly more likely than the bullshit he spun out, as it’s actually possible…

I’m certain (or at the very least hopeful) that the actual “reveal” will come later on in the series… but in the mean time, he did show one very cute mathematical trick for winning a coin game.

This is the game:

  • Player 1 chooses a 3-coin combination, say Tails,Tails,Heads
  • Player 2 chooses another, for example Heads,Tails,Tails
  • We now throw a series of coins until one of the players’ combination is thrown in order.

You might think, given that any 3-coin combination is as likely as another (will be thrown with a 1/8 probability) that there’s nothing to choose between them. But notice that I didn’t say you threw 3 coins at a time! For example, if we throw.

  1. Tails
  2. Heads
  3. Tails … at this point we’ve thrown 3 coins, and matched no combination
  4. Tails … and now player 2 has won: coins 2-4 read Heads,Tails,Tails

If you look at these 2 combinations, you’ll see that Player 1 will win if the sequence goes: Tails,Tails,(any number of Tails), Head. Player 2 will win in any other situation, i.e. 75% of the time.
The combination the hapless participant chose (Heads,Heads,Heads) is even worse, losing 87.5% of the time!

It’s about time for me to try modelling a problem in Haskell, so let’s try this one!
I find the docs for System.Random rather confusing, but found some inspiration from a
haskell-cafe post about random coin throws and encouragement on #haskell from Luke30, Twey, and others.

I won’t go through the code in detail this time, but here are some key things to note:

  • the randoms function returns an infinite stream of random things. In this case I’m using it as a stream of Bools, like [False, True, True, False, True, ...] and then converting them into [Tail,Head, ...].

    lilac pointed out that I could create an instance of Random for Coins, I’ll have a look at that soon.

  • I’m using tails (nicely overloaded vocabulary ;-) to iterate the infinite sequence of coin flips, stopping when one of the players’ sequences matches.

And here’s the code:

import System.Random
import Control.Monad
import System.IO
import Data.Maybe
import Data.List

data Coin = Head | Tail
    deriving (Eq, Ord, Show)

-- Derren Brown's coin game.
-- The second winner has chosen a combination that will win
-- significantly more often

main = do
    g1 <- guess
    let g2 = counter g1
    putStrLn $ "Player 1 chooses " ++ (show g1)
    putStrLn $ "Player 2 chooses " ++ (show g2)
    coins <- coinFlips
    let winner = take 1 .  catMaybes .
                 map (win g1 g2) $
                    tails coins
    putStrLn $ "Player " ++ (show winner) ++ " wins!"

guess = do f <- coinFlips
           return $ take 3 f

counter [a,b,_] = [rev b, a, b]
    where rev Head = Tail
          rev Tail = Head

win g1 g2 l | g1 `isPrefixOf` l = Just 1
            | g2 `isPrefixOf` l = Just 2
            | otherwise         = Nothing

-- modified from
-- http://www.haskell.org/pipermail/haskell-cafe/2005-April/009687.html
coinFlips :: IO [Coin]
coinFlips = do g <- newStdGen
               let bools = randoms g
               let coins = map bool2coin bools
               return coins
      where bool2coin True  = Head
            bool2coin False = Tail

The moose counts beans – managing my finances with Perl

I’ve recently been trying to improve my rather disorganized personal finances.
While I previously “managed” by leaving the bulk of the money in my account
and hoping that I’d calculated my expenses versus salary roughly correctly,
this is suboptimal for answering various questions like “Do I have enough
money to go on holiday?” or “Have I forgotten to pay the electricity bill
for the last year so that I now have to pay it back?”

Clearly there is a better way. Checking off expected payments, knowing what’s
due in the next week/month/etc., and siphoning off the excess into a linked
savings account for example. But this requires being alert and accurate…
Failing that, I could always use a computer ;-)

Spreadsheets

Surprisingly perhaps, the humble spreadsheet is an instrument of frustration
for this kind of task. I’m currently using Google Docs, which is underpowered,
but not really much more hateful than Excel or OpenOffice.org.

It’s particularly bad at being a working document. Moving an item (to
reschedule the date, for example) involves:

  • inserting rows
  • cutting and pasting
  • deleting the original rows
  • changing the date
  • “filling” down the subtotal column (because spreadsheets don’t have the concept of a calculated column).

Worse yet, because spreadsheets don’t know about dates, adding regular
payments (bills, weekly spends etc.) is an exercise in manually creating them,
and then visually auditing the sheet to make sure you put them in the right
places.

Other apps

Of course dedicated apps for personal finances do exist. I looked at the
Linux ones, Gnucash, Kash, etc. Mostly they crashed. Sometimes they ran
but utterly confused me. And then crashed.

There are also web based ones. My initial survey of these suggests that
they are prettier and easier to use, but perhaps clunkier, or tied into
specific bank systems.

Beans means…?

So, being a programmer, the obvious answer is to attempt to roll my own.
As a learning exercise ;-) Though I’ll attempt various sketches of this in
Haskell, I’ll start off by trying to implement it in Modern Perl:
specifically the
Moose
OO framework, using various niceties such as
the pretty declarative syntax of
MooseX::Declare.

Every project needs a good name! But this is just a learning exercise, so for
now I’ll call it “Beans”.

I’m hoping this will end up an ongoing series of posts, please feel free to
follow along at the
Beans git repo if you like,
or to suggest improvements, for example:

  • a better project name
  • shinier ways to do this in Moose and Modern Perl
  • how this would be more elegant in Haskell/Lisp/etc…

As always, these posts will be fairly rough drafts, I’m hoping to tidy this up
into a more finished article soon, so any comments are really welcome to help
me polish it up!

Declarative code

In this installment, I’ll just define a data type for a line item in Beans.
You can see the current code as of this evening,
but let’s look at it in detail here.
We’ll start off by using Moose, and declaring our class:

use MooseX::Declare;

class Beans::Item {
    ...
}

Now we’ll want to declare some fields for our class. For example, every
payment made or expected will have a value:

    has value     => (
                       isa      => Num,
                       is       => 'rw',
                       required => 1,
                     );

What’s that? Perl has types?! Yes indeed, Moose gives us types, and
automatically validates against them. So when we try to create our object,
we’d find that:

    my $obj = Beans::Item->new( );                # fails, value is required!
    my $obj = Beans::Item->new( value => "foo" ); # fails, "foo" is a string
    my $obj = Beans::Item->new( value => 10.00 ); # OK! 10.00 is a number

I’ve cheekily missed out a few details though… Num isn’t a Perl
builtin keyword, so we’ll need to import it. In fact, while we’re at it, let’s
pull in Str too, so that we can add a couple of string fields at the
same time:

    use MooseX::Types::Moose     qw/ Num Str /;

    has name      => ( isa      => Str,
                       is       => 'rw',
                       required => 1,
                     );

    has comment   => ( isa => Str,
                       is  => 'rw',
                     );

Now we also want to be able to add the date of the expected payment:

    use MooseX::Types::DateTime  qw/ DateTime /;

    has due_date  => ( isa      => DateTime,
                       is       => 'rw',
                       required => 1,
                     );

This means we could do

    my $obj = Beans::Item->new(
        value    => 10.00,
        due_date => DateTime->new(
            year  => 2010,
            month => 6,
            day   => 30,
           ),
      );

        # but I'd prefer to be able to do
        due_date => '2010-06-30',

And we can indeed make this prettier using coercions!

    use DateTime::Format::Natural;
    my $dt = DateTime::Format::Natural->new( prefer_future => 1 );
    coerce 'DateTime'
        => from 'Str'
            => via { $dt->parse_datetime($_[0]) };

    # We'll need to tweak the due_date declaration too...
    # (coercions don't run unless you ask for them)

    has due_date  => ( isa      => DateTime,
                       is       => 'rw',
                       required => 1,
                       coerce   => 1,
                     );

While every line item will have an expected due_date, we’ll also want
to keep track of what date the item was actually paid, if it has
been paid. As this is uncertain, we use the Haskell-inspired Maybe
type. (As far as I can see, this isn’t actually as powerful as Haskell’s
Maybe monad, it’s more like a nullable type).

    use MooseX::Types::Moose     qw/ Num Str Maybe /;

    has paid_date => ( isa => Maybe[DateTime],
                       is  => 'rw',
                     );

Once we’ve got this type, we can calculate a boolean field based on it.
The paid field will be true if paid_date contains anything,
and false otherwise. Let’s try defining it like this:

    use MooseX::Types::Moose     qw/ Num Str Maybe Bool/;
    has paid      => ( isa => Bool,
                       is  => 'rw',
                       lazy => 1,
                       default => sub {
                            my $self = shift;
                            defined $self->paid_date
                          },
                     );

The default code block gets called the first time we ask for
the field. There are a couple of problems with this of course – once it’s
set, if we change the paid_date, this field won’t change. We’ll come back to
this later, but here are some ideas:

  • change it into a method
  • use immutable objects, so that setting this lazily on first request is
    always the right thing to do

  • use triggers to update paid when paid_date is set
    (and vice versa! setting the boolean flag could set the payment date to
    today’s date, for example).

Now, though we specified that the name should be a string, nothing is
preventing us from passing the empty string ""… but Moose allows
us to define a better type constraint here too!

    use MooseX::Types -declare => [qw/ NonEmptyStr / ];
    subtype NonEmptyStr
        => as Str
            => where { length $_ };

    # so now we can modify this definition to:

    has name      => ( isa      => NonEmptyStr,
                       is       => 'rw',
                       required => 1,
                     );

>

Finally, let’s add a list of tags. Just for now, we’ll define these as an
array of non-empty strings:

    use MooseX::Types::Moose     qw/ Num Str Bool Maybe ArrayRef /;

    has tags      => ( isa      => ArrayRef[NonEmptyStr],
                       is       => 'rw',
                       default  => sub { [] },
                     );

Notice how we’re using default again to set the default value to
an empty array.


That’s it for now! Next time around we’ll maybe look at parsing and displaying
line items, and start to do useful things with them.

YAPC::EU::2009 Lisbon writeup

The Portuguese team did a fantastic job with this year’s Perl conference YAPC::EU::2009 in Lisbon
just last week.

What I learnt

  • Lots of companies — Cisco, Opera, the canton of Geneva, among others — are proud to use Perl.
  • There is lots of work going on in the “Enlightened” Perl movement. Including ways to make deployment and packaging of Perl apps easier. You can join the EPI for a mere GBP 100/year (whether you’re UK based or not) and can pay by regular direct debit.
  • Perl is “Alive and kicking, and stronger than ever”. (OK, that’s marketing speak.
    But Barbie’s talk on the statistics of Perl
    backs it up: for example there are between 30 and 50 new authors
    uploading their first module to the CPAN every month!)

  • As always, the hallway track is one of the best parts of any conference -
    the chance to meet up with old friends and colleagues, and make new contacts
    with the very clever people in the
    Perl community and find out what they’re doing.

Cool modules mentioned included:

  • Moose, MooseX::Declare, etc.
  • TryCatch
  • XML::Pastor
  • autodie
  • autobox, and MooseX::Autobox
  • Regexp::Grammars (very cool indeed, from the Damian – Perl6 like rules, in Perl 5)

Logistics

Joel++ booked a flat (via waytostay.com) for 5 of us. This was an
excellent idea, reasonably priced, and a beautiful flat, great for
socializing in. Highly recommended, especially for a group of
friends/colleagues.

Organizers

The Lisbon team did a fantastic job! Among their several innovations, were such delights as:

  • Coffee/lunch all the time: this was very bare bones, but none the worse for it. There was food any time you wanted it, which meant that you never had to worry about leaving a talk late etc. This was especially useful given that the campus wasn’t right next to large restaurants. (But even in central venues, if 300 people go out to lunch, they will be gone for 2 hours, realistically).
  • The Quizz show, hosted by Damian Conway at the conference dinner. (One of the orgas)++ had hacked some PS2 games controllers, and great fun was had by all.
    (Me and Polettix came 2nd, but the important thing is that we answered a Buffy question first, to the horror of davorg and Greg).

  • Moderators in the auditorium (Wendy++ and Liz++).
  • “Special” namebadges with an information booklet inside.
  • sapo.pt sponsored a lovely chillout area with wonderfully comfortable beanbags.

They set a worryingly high standard especially as…

YAPC::EU::2010 will be in Pisa

I seem to have got myself involved in this… but it’s going to be great. Look forward to seeing you all there!

Functional Pe(a)rls and Foose

I gave the href="http://www.slideshare.net/osfameron/functional-pearls-4-yapceu2009-remix">fourth
version of my Functional Pe(a)rls talk, which went down quite well. Thanks
to everyone who showed up, especially for putting up with me being late…

I’ve been apologizing for some time for not having actually sat down and
released modules for all the techniques I’m playing with here. But James Laver
finally pestered me enough, and we’ve created a new project: href="http://github.com/osfameron/Foose/">Foose (working title, in homage
to Moose) which will aim to bring neatly packaged functional goodness to Perl.
(See also irc:irc.perl.org/#foose)

Moving on

I attended YAPC in the last week of employment with Thermeon Europe,
who kindly paid for my time there. It’s been a crazy 2 years (almost), and I’ll miss the guys there, but I’m
excited to be moving on to consulting, initially on some Perl development and documentation projects.

If you’re interested by anything you’ve read in this blog and would like to hire me, then please do get in touch ;-) I’m mainly interested in teleworking or contracts in Northwest UK, but happy to discuss!

A brief note on technical translation: Jay Kuri’s Gentle Introduction to Moose

While we were discussing how to promote the Italian Perl Workshop, and
the planned href="http://conferences.yapceurope.org/ipw2009/news/422">training on
Moose, I noted that there weren’t any articles on Moose (Perl’s
modern OO implementation, inspired by CLOS, Smalltalk and Ruby) on
perl.it. Lordarthas of course told me “well volunteered!”… oops.

I pointed out that I don’t really know Moose, and we eventually agreed
that I would “just” translate Jay Kuri’s nice new href="http://www.catalyzed.org/2009/06/a-gentle-introduction-to-moose.html">Gentle
Introduction.

Now, there is a reason why translators almost always translate
into their native language. I can write in Italian
reasonably well, but translating into it was a much harder task.
While you’re writing something yourself, you tend to route around
phrases you don’t know how to express, choose different words, simplify
structures, etc. But translation implies some degree of fidelity
to the source, and I found this incredibly hard going. I whined on
#perl.it and, in true Open Source JFDI style, larsen asked
“Huh? Why are you translating that?” and did it himself! Yay,
larsen++!

So my volunteering ended up being limited to making a few
corrections/suggestions, along with lordarthas, dree, and dada.
Opensource translation and review (using wiki/email in this case, but a git repo or
similar could work just as well) can have a fast turnaround, and pick up
many errors/nuances that a lone translator would have to work really
hard on to do by themselves.

An interesting problem with the technical translation was deciding which
phrases to leave in English, and which to translate. Looks like “coercion”
is staying in English (followed by an explanation) instead of using the
Italian “coercizione”. And the title is surprisingly hard to translate,
as none of the words for “gentle” map well into Italian. Though it’s
less cute than the original, the least awful alternative seems to be
“Una breve introduzione” (a brief introduction).

The final translated article is now on perl.it!.

Bids for YAPC::EU::2010 – Pisa and Kiev!

Organizing a conference is hard, let’s go shopping! For the first time I’m
officially helping, not just for the Italian Perl Workshop this year, but
possibly for YAPC::EU::2010 too. I’ve been working with the href="http://perl.it/">perl.it guys on the proposal to host the European
Perl Conference 2010 in Pisa.

We submitted the bid on Monday, and it’s
just been announced
that the teams competing are: Pisa (us) and Kiev in Ukraine. Wow! YEF have actually
published both our bids on that link, which is fantastic for transparency.

It also means that we can read their bid… and it’s a good one! Looks like
we’ve got some competition. Of course our Pisa bid is excellent too – in
any case, the next couple of weeks till we find out who won are going to be a
nailbiting time!

News on IPW2009 – DBI, Perl6, Javascript and… Dave Rolsky?

The preparations for this year’s Italian Perl workshop are hotting up, and it’s looking like it might even top last year’s event. I’ll just focus on the international track (in English) here: we’ve already got some great guest speakers lined up:

  • Tim Bunce, the author of DBI, one of the finest database interfaces known to man. Tim is also a smashing bloke, and this is his return invite to the IPW, by popular demand!
  • Jonathan Worthington, one of the core devs for Perl 6 (Rakudo and Parrot VM).
  • Thomas Fuchs, Javascript guru – who says Perl conferences are just about Perl!
  • Amy Hoy/Fuchs, user interaction and product design expert.

And we have at least one other tempting (but not yet confirmed) morsel up our sleeves…

Dave Rolsky (autarch) on Moose…?

Moose is a “postmodern OO system” for Perl. If you love LISP, you might be interested to know it’s based on CLOS. If you love Smalltalk, you might appreciate its use of Roles. In any case, Moose is full of awesomeness, and is currently making Perl OO look way more attractive and powerful than it used to…

Dave Rolsky (autarch) is one of the core Moose devs, as well as the author of DateTime and HTML::Mason among others. We’d really like him to talk at the IPW, but there’s just the small matter of paying his airfare from the States… Luckily, he’s willing to give a special paid day’s training on Moose, probably on Wednesday 21st October, the day before the conference. If we can get enough participants, we’ll be able to invite him for the workshop too…

All the details are in this
announcement, but I’d just like to point out:

  • The ticket price (likely to be 100 Euros for the day) is ridiculously good value compared to the normal going rate – that’s because it’s a “grassroots” price, solely for the purpose of paying his way to talk at the Italian Perl Workshop (which is entirely free!)
  • Dave doesn’t get to Europe much. In fact, up till now, never – so this is a very rare opportunity.
  • Pisa is really central – you can fly there from a massive number of European cities, often direct, and often with a choice of traditional or low-cost airline.
  • There will most likely be a whole track in English: as well as the guest speakers I mentioned above, there’ll be others. For example, I’ll probably be speaking… why don’t you submit a talk too ;-)

If you’re interested, please email info@perl.it.

Global state in Web Applications: Catalyst’s stash.

The Perl web framework Catalyst has, and I’m fairly sure this is in
common with many such frameworks in any programming language, a concept
of a store of data, scoped to the current request, called the “stash”.
I’ve mentioned a few times that “I don’t like it” and the reaction I get
suggests that I don’t understand it. So it’s a good time for me to be
ignorant in public so some clever people that do understand can
tell me what I’m missing ;-)

Global status

I say that the stash is “request scoped”. But really, for the lifetime
of the web request, it’s a big global pile of random data. Some things
would naturally seem to fit there: big things to do with global status,
like the logged-in user. So, for example, a base action might check for
POSTed login details, and for session cookies, and set
$c->stash->{user} to a MyApp::User object.
Then, further down the line, another action might want to read user
details, and can do so by retrieving it from the stash.

This may seem very convenient. But of course, being in a hash, we don’t
get certain protections. For example, should later actions be
able to read the user object? Should they be able to modify it?
What about typing? What if someone sets {user} to a String, or
an undefined value? It really seems like it might be better to model
this kind of global status as an object, for example:

    use MooseX::Declare;

    class MyApp::Status {
        has 'user' => (
            isa       => Maybe[ MyApp::User ],
            predicate => 'is_logged_in',
            is        => 'rw',
            coerce    => 1,
            );

        coerce 'MyApp::User'
            => from 'Str'
            => via { return MyApp::User->from_name($_) };
        coerce 'MyApp::User'
            => from 'Int'
            => via { return MyApp::User->from_id($_) };

        ... # other global status things
    }

This way we get lots of modern/enlightened/whatever Perl OO niceties
like coercion, and methods built for free, like is_logged_in.
We could also provide a custom accessor that didn’t allow the user to be
updated if it’s already been set, etc.

Passing information down the chain

I mentioned that a base action could set the logged in status near the
beginning of the request. In fact, this is a common pattern in many web
frameworks, with a whole pipeline of actions happening in order. For
example, Catalyst has “chained actions”, where a URL like

    /client1/documents/invoices/23

might build a chain like this:

  • login
  • admin login
  • client specific customizations
  • document template setup
  • invoice template setup
  • fetch invoice number 23

It’s unlikely these days that you would write:

    method handle client1_documents_invoices ($invoice_number) {
        $self->login          or return;
        $self->check_is_admin or return;
        my %client_args = $self->do_client1_customizations;
        my %template_args = (
            $self->document_template_setup(%client_args),
            $self->invoice_template_setup (%client_args),
            $self->fetch_invoice( $invoice_number ),
            );
        $self->process_template( %template_args );
    }

That would be ridiculous, as you’d have hundreds of such methods… one
of the major selling points of a framework is to allow you to combine
these little pieces flexibly and elegantly. So you end up with the
elements in the chain as separate actions… But how do we manage the
flow of data between these items (the %template_args and %client_args in
my contrived example above, for example) ?

We use the stash of course! So each action can read the values it needs
from the stash, and write things later actions will need back into it.

    method an_action_in_a_long_chain () {
        my $foo = $c->stash->{foo};
        my $bar = do_something_to( $foo );
        $c->stash->bar( $bar );
    }

Hurray! Except that you may have noticed that we’ve reinvented passing
formal parameters and return values using global data. Welcome to 1959,
enjoy your stay in COBOL!

And of course, if we get parameters via the stash, we lose the benefits
of typing. And we have to be really certain that the bit of global data
we want has been set by the time our action gets called. And, because
we have a global namespace, we have to hope that some other action in
the meantime hasn’t set the value to the wrong sort of data.

It also leads to us thinking about our data as singletons. When we
realise later that we need to call an action on two separate objects,
what do we do? We only have one global slot for the parameter name, so
we now have to set it twice (or localize it), and we have to squirrel
away the first return value before it gets overwritten (yuck)!

Spaghetti and action-at-a-distance may not be the intent of the stash,
but they do feel like the logical progression of the concept to me.

Template values

Perhaps the least heinous usage of the stash is as the final store of
data to be sent to the template. Each action in the chain will set some
information:

    $c->stash = {
        # set by a navigation component
        breadcrumb => [ 'client1', 'documents', 'invoices' ],
        menu_items => [ 'save', 'edit', 'delete' ],

        # set by the login action
        username => 'osfameron',
        usertype => 'admin',

        # set by the invoice action
        invoice_data => $MyApp::Model::Invoice,

        ...
        };

Again though, what’s to prevent one action from stomping over the
other’s data? Will the template die if it gets a hash for
invoice_data instead of a MyApp::Model::Invoice
object? What happens if some data it was expecting never got set?

What’s the alternative? I suspect that a “widget” approach might be
saner, and I have to confess I still haven’t looked at Reaction yet:
perhaps that’s what I’m looking for?

How do other frameworks deal with this?

I’m not, by the way, bashing Catalyst in particular – it’s what I’m
using now, but the frameworks I’ve used or written in the past have also
had the features of pipelines of actions, and some kind of flattened
global state (whether it was a stash, or just a hash that was passed
down the pipeline). Given the problems I’m seeing, I can’t believe that
this is the final goal, or even the state of the art. So:

  • What am I missing?
  • How does your framework deal with these issues more elegantly?
    (For that matter, how does Catalyst?) I’m especially interested in learning about how strongly-typed FP stacks (HAppS?) confront this stuff.
  • Where next?

Is currying monadic?

Here’s a question that came up while I’ve been trying to
href="http://greenokapi.net/blog/2009/05/04/currying-in-perl/">implement
currying in Perl: is Currying monadic?

I’ve tried a couple of times, but not managed to explain what I mean very well on #haskell, so let’s
see if a longer writeup explains it better.

My simplistic understanding of monads is that they take various things that
are nests of nested expressions, and allow you to reason about them, and
given them a pretty syntax that makes it look like they are in fact a
sequence of commands.

For example: (pseudocode)

    let a = 1
    let b = 2
    output a+b

Looks like a sequence of commands, but you couldn’t just separate each
line and string the commands together. Rather you have to consider it
as a nest:

    (let a = 1
        (let b = 2
            (output a+b )))

And in many cases, we can go from a nested structure to a monad, for example, we could simplify these horribly nested ifs:

    (if file exists
        (if file is readable
            (if reading the file gave a string
                (if the string matches a username
                    (do some action with the username)))))

… into a nice Maybe monad:

    do check file exists
       check file is readable
       string <- read from file
       check string matches username
       do something with the username

Similarly, nested lists:

    (for each i in list 1
        (for each j in list 2
            (is i the same as j?
                (output i))))

can be abstracted as a List monad:

    do i <- list 1
       j <- list 2
       check i == j
       output i

OK, so I'm not talking about wrapping and unwrapping values, the monad
laws, or typing in general. They are what gives this stuff its strong
theoretical basis and makes it robust. But the simple-minded "Nest ->
Sequence" idea works for me at least, and gives a good feel for
where monads can come in useful.

Currying

So... when I was implementing currying, I noted that you could write a
currying sub (pseudocode again):

    function add3 (a, b, c) {
        return a+b+c
    }

as something like this:

    function add3 (a) {
        return function (b) {
            return function (c) {
                return a+b+c
            }
        }
    }

This is again a nested expression. So I wondered if you could again "flatten" it with a monadic do block:

    let add3 = do
        a <- get first parameter
        b <- get second parameter
        c <- get third parameter
        return a+b+c

OK, so I "know" that functions in Haskell (which uses currying for
functions as a general rule) are the "Reader monad". But I don't
understand it well enough to know if that means you can use Reader to
implement the above...

(I don't understand Reader at all in fact. I must bang my head against
it again, but I find it very confusing - how the monad is represented,
what the functions are, and how they get magically applied.)

So, I did attempt to implement it using my Perl module
Acme::Monads. This href="http://github.com/osfameron/acme--monads/blob/master/t/04_curry.t">test
shows that this sort of works:

    my $add = mdo (2) {
        mbind $x = Curry shift;
        mbind $y = Curry shift;
        return $x+$y;
        };

    say $add->(1)->(2); # 3, yay!

Note that the "return" isn't a monadic Unit but Perl's return,
i.e. a plain value. That makes this example strictly speaking not
monadic: what I don't know is whether that means the whole idea is fatally flawed, or whether (as I believe) I was just too dumb to fix the errors I got when I tried running with munit...
I suspect that it should be possible, with the
whole expression then being wrapped by some function
(runCurry?) which extracts the final result out of the monad.

Did this explanation make any sense? Please let me know, and any
comments on whether it's possible/sane to do this (writing currying as a
monad) are appreciated!