Perl, Haskell, stuff
First of all, a disclaimer: I know "larsen" (Stefano Rodighiero) not just as an
ex-colleague (he is one of the most respected senior programmers at DADA in
Italy), or through the Italian Perl
community, but also as a good friend.
But of course, those were excellent reasons to look forward to his book: an
introduction to Perl in a pocket series of roughly the same format and price
point as the UK Teach Yourself
series. The community's perl.it website lists
various resources including tutorials and books in English and Italian, but till now
they haven't recommended an introductory book in Italian. I think that could be about
to change.
"Imperative programming... in Pure Perl!"I think the talk went down well and I also won a book (of maps of Old London Town) from the nice people at Nestoria for "Best Topic", which I guess means I can refer to it as an "award-winning" talk.
I've uploaded the slides of my award-winning talk on functional programming in Perl to slideshare ;-)
It was great to see some quality talks, a uniformly excellent lineup of lightning talks (including one which broached Italy's candidacy for YAPC::EU::2010), meet up with old friends and colleagues, and put some more names to nicks and faces.
Update 2009-02-06: Mark uploaded the videos from room 1 this week, and today they're up on yapc.tv, including Functional Perls. Yay, mdk++, andy.sh++! The sound is better than many conference videos, so you can hear me um and er in high quality, but the slides aren't included on the video, so you may wish to follow along on slideshare or download the slides.
I've never studied Python, but I'd quite like to at some point in the future. It seems very much like Perl with a different set of design criteria. Yeah, there are differences, but compare with C, Lisp, COBOL, and you can see why Perl and Python are clustered together in the "P languages" (Perl/Python/P^HRuby etc.)
Actually, that's one of the main reasons I've not expended signifant effort into learning Python - I can hurt my brain far more by trying to learn C or Haskell. But I'm sure it would be a good thing to do at some point. Here are a few notes on first impressions: these are just that, impressions, and may not be factually accurate: if you want to know full and correct details about Python, there are many excellent blogs that will clarify.
2008-09-25 Thanks for the excellent comments, I'll fold in corrections below!
(2008-09-25: Bill Mill points out that map remains; reduce got moved to Standard Lib, as comprehensions already do the right thing; and grep doesn't exist. Is that called "filter" in Python? Of course comprehensions can already to map/grep too)
On the other hand, python has list comprehensions which work equally well on lazy generators! Very nice indeed. It also has a much fuller destructuring bind than Perl's (which only works on single-level lists). So some good, some bad, and some interesting syntax and features. I doubt there's a clear "winner", some more discussion on Perl/Python (via Lisp of course) in Paul Graham's Revenge of the Nerds post.
Oh, and Python has continuations! With a builtin yield command. Perl has the Coro module, which is a fantastic piece of work, but rather complicated with confusing documentation. The yield command itself is in Coro::Generator but it has a number of limitations, like not being able to clone a continuation. There was a lovely post on creating monadic "do-notation" using continuations only, and I ported it to Perl with much swearing only to find that though it worked great for simple monads, it failed utterly for the List monad (important as it's what list comprehensions are built on) precisely because of this. Apparently the Perl internals don't really mesh with this, so it's unlikely that we'll be getting it for Perl 5 any time soon. Point to Python.
(2008-09-25: dolio points out I'm confusing generators and coroutines. Yup, I do that, sorry! I think one can be implemented in terms of each other (and vice-versa?), and that some literature does also blur the distinction, but could be wrong about that too? And yes, Ruby has callcc, but apparently the Monad example I was reading can't be easily ported to Ruby because the continuations/coroutines/thingies generated by yield aren't clonable)
Will on Geekup posted some nice examples of "declarators on attributes", which I think are similar to lvalue tied methods, but look rather better designed. (From Damian Conway's talk Contextual::Return may fix the problems Perl has with this kind of nice syntax. I say may as with Damian's talks it's hard to tell whether they truly are a massive advance in usability and functionality or crack-fueled insanity). Actually, declarators deserve their own section:
But talking about declarators, I have to ask:
Some differences I've heard mentioned include (with no figures or such to back them up...):
There is a constant meme that Python is somehow more "modern" than Perl. This is almost never qualified, I remember in this interesting book on programming language design that it was mentioned that the fact that Python's regular expressions lived in an external module was a more modern design that Perl's, which had them as builtins. Perhaps Perl not building in support for declarators and list comprehensions is more modern too? I'm sure if I say this often enough, it'll be a good substitute for actually making sense :-)
But Python does seem to get more buzz, with things like Google's AppEngine supporting Python before Perl. Hey ho. I still think that there are many more Perl jobs going, for what that's worth.
Off the top of my head, there's Twisted, Python's equivalent to POE; Django (Catalyst); and PyGame (possibly comparable to SDL_Perl?) as fairly high-profile complex libraries that show, to be honest, that both languages are pretty healthy with regards to module support.
(2008-09-25: Bill Mill points out PyPI link, and admits it's "still no CPAN, but it's coming along", which is more or less what I was trying to suggest ;-)
I went to my 3rd Italian Perl Workshop, IPW2008 at the end of last week. It seems to have been the most successful Italian conference to date, and it certainly succeeded at being both a national workshop and an international event. It hadn't occurred to me before that these are actually two orthogonal aims.
The organizers managed to pull out all the stops with sponsorship. There's always various random swag, books for the auction, cheap/free use of rooms from the University. And in recent years, the conference has had just enough money to be completely free of charge, even with its (excellent) coffee and biscuit break. But this year, the "platinum", "gold" and "silver" sponsors contributed enough money to pay travel and accomodation for speakers of international calibre:
Other international attendees included Michel "XML::Twig" Rodriguez (though he lives in nearby Lucca and spoke in Italian); Bruno (a Pole who lives in Spain... or Amsterdam or something... I'm confused, especially as to why he attended the Pisa workshop :-); a bevy of Norwegians from Opera's HR team; and another Norwegian expat who was completely unrelated; an Indian postgrad studentessa; and me, I guess.
Hmmm, 4 Norwegians, 3 Brits, 2 French. I wouldn't have expected quite that many Norwegians, largely because I'd never have thought that Opera, based in Oslo, would have been recruiting at a workshop in Italy. But it's on their "world tour" as several of the core Perl team for their social network are Italian. And they really capitalised on the opportunity, sending 3 perlisti and 2 HR, all of whom were very visible throughout, sponsored a competition for a Wii, and hired an interview room for recruiting sessions during the workshop. I'll be really interested to see how successful they, and the other recruiting companies (Wind, Dada, A-Tono) have been. It's very positive that Italian companies using Perl are getting involved like this.
Oh, the talks! Matt spoke about Devel::Declare, which rocks. I finally got to see Tim Bunce's Perl Myths talk in the flesh, and also his demo of Devel::NYTProf which is so beautiful it makes me want to cry. Marcus introduced Catalyst, and I missed the others, for various reasons.
There's a danger that the focus on the exotic allure of geeks arriving by luxurious Ryanair jet could distract from the fact that this is also the event for Italian programmers. Having two tracks, and a general policy of not scheduling 2 "guests" against each other worked very well here.
The first day's Italian talks concentrated on beginner and intermediate topics, including dakkar's tutorial and regex theory, and Flavio Poletti on writing IRC bots, though there was some crossover, as rgs also presented on coding style in English. The perl.it guys are really keen on appealing to new programmers, which is fantastic. (There was a little gnashing of teeth about how the recent Pycon in Italy had even more attendees despite being a younger conference.)
Not that it was all for beginners: emi spoke about Linux wifi captive portal setup; emazep showed a fantastic UI for constructing complex DB queries, running on Catalyst with jQuery; grubert presented a news portal prototyped in 2 months with the awesome power of CPAN; [LucaS] finally presented his workgroup software IGSuite, yay! Cosimo spoke about scaling and the Dogpile Effect at Opera. Sadly I missed the "GUI track" completely with Mattia Barbon, the author of WxPerl, and nids talking about Perl/TK. And finally I had to give an emergency talk myself to fill in a gap (went OK, trailed off towards the end).
One of the questions in a recent survey on rec.arts.int-fiction asked if we preferred "story" or "puzzle" interactive fiction. Though it's not as much of a binary choice as the wording implied, there are two extremes of a continuum, and many people have a preference towards one end or the other.
I'm not a very big IF player, but I did get into the competition in 2004, when I played and voted on every z-code game and many of the others. My favourite games were Blue Chairs and Gamlet. Both had great writing, lots to do, and, when they tried to do puzzles (Blue Chairs's midsection, the second half of Gamlet) lost it completely, requiring judicious use of the walkthrough to be able to continue the story.
I completely bypassed the puzzle-based scifi game, All Things Devours, the first time around: I'd found it an unappealing combination of boring, hard, and confusing (I died repeatedly, without ever having understood what it was I was meant to do). It turns out ATD placed 3rd, just after Blue Chairs, and after reading some rave reviews of it, I decided to give it another shot. That time I managed to get into the lab (previously I'd missed the buttons that opened it) and managed to blow myself up once or twice before getting bored.
Now the premise of the game sounds interesting: you have to travel back in time, but while you're there, you can't meet your future self or Bad Things will happen. My problem was that I couldn't even work out how to use the time machine...
Just recently, interest in IF briefly sparked again, I decide to give ATD another go. I'm momentarily put off by the fact that setting the "timer" doesn't mean the one on the time travel device, but the one on the bomb I'm carrying. Oops. So I have to set the panel? But what to? I try random numbers between 1 and 500 and end up dying. So I resort to a walkthrough. It's a number of seconds (why the game can't tell me this, given that the PC I'm controlling invented it, I don't know). I calculate the right number of seconds, press the button, and vow to actually pay attention to the time reported in the status bar. Then I start wandering around and, yes, the game is actually very clever (as I've heard, but not experienced first hand up until now), you die if you see your future self, or if that self discovers part of her world universe in an inconsistent state. My resolve to stick at this with a map and a list of times and object locations vanishes after dying twice.
I'm not trying to criticize ATD by the way: people whose opinions I trust have said great things about it, and I have tried really hard (well, fairly hard, but a number of times at least) to get it. It's just much further inclined to the puzzle end of things than I'm comfortable with, hey ho. If you've not played ATD, then go and play it now, you might well love it (but play Blue Chairs too!)
Oddly, I love Spider and Web, and that has some really difficult puzzles too. Now some of them I got by myself: getting in and out of the scanweb, and that puzzle. But others (the clattering lockpick) completely baffled me. I don't get the world model well enough to know when my actions will do the right thing, especially when they're about timing (which is an odd thing to do without detailed visual/sensory stimulation to work with). But, in the main, though I don't really get on with puzzles, you're given a gentle training in the use of the gadgets. And I loved how the game deflates your progressive attempts to do things like learning how to shut down the scanweb to sneak across the gun. So having to resort to a walkthrough to work out the frustrating "boring" puzzles is actually worthwhile: because it gives you a payoff including more clever and fun puzzles, the NPC interaction, and the aha moments of the unreliable narration. OK, so the endgame doesn't work for me: yes, it's nice to see what use the PC actually made of various gadgets and hiding places, but now you're working without the training wheels of the interrogator to tell you what you "actually" did. (I'm torn between wishing on the one hand that the dash through the facility was more "on rails"; and on the other that I'd taken a deep breath, mapped it, and realised that the basic principle was "look at all the places that have been signalled in unreliable narrations" and solved the puzzle/story myself).
But no matter, the first half of Spider and Web has set things up, it's earnt the right to have a cruel and boring timed puzzle. I'm not sure it quite deserves the final lab puzzle though, oh well...
The r.a.i-f thread I linked above has some more discussion about the dichotomy/continuum of puzzle/story IF. If you haven't already read/played modern IF, then it's worth looking at a number of different styles before making an opinion on this varied form! (And if you play IF, where do you fall in the continuum?)
(Cross posted from my use.perl blog)
The Italian Perlmongers are finalising their preparations for IPW 2008, Pisa. I managed to get to the last 2 while I was working in Florence, and the organizers have always managed to get a great venue, coffee breaks with unusually nice biscuits, and put on a fantastic mix of talks and a lively hallway track.
Like all the national conferences, talks in previous years have been largely in the local language, with maybe a handful in English from expats and visitors. This year though, the organizers have also managed to get great sponsorship from Opera, Booking.com and others and as well as making the conference free, they're able to sponsor some fantastic guest speakers. Bepi has already confirmed:
Some notes on logistics if you're thinking of travelling to Pisa from outside Italy:
a list of numbers like 10,25,50,100,250,500,1000,etc without tracking any other state than the number itselfNope, this isn't A020179 but the much more prosaic A112024. Debolaz wanted this sequence, or something similar to it, for the same reason the US used it for currency - the numbers are human meaningful, and are useful as the numbers get exponentially bigger: in his case, for the labels for a chart. This may not be the most interesting of sequences, but, as autarch pointed out, there are many algorithms that work, and exploring some of them is fun and/or instructive.
sub seq_1 {
my $n = shift;
my $val = 10;
my @ret;
for (1..$n) {
push @ret, $val;
$val *= $val =~ /^1/ ?
2.5
: 2;
}
return @ret;
}
say for seq_1(10);
autarch suggested dividing by 10 until you get to 1 (or not) as an alternative.
So we were back to a state variable like the position of the element in the sequence.
map { 10 * 10**(int $_/3) * [1,2.5,5]->[$_ % 3] } 0..10
That is to say
10 10 10 100 100 100
* 1 2.5 5 1 2.5 5
= 10 25 50 100 250 500
i.e
10 * 10 ^
0 0 0 1 1 1
*
1 2.5 5 1 2.5 5
Not much else to say really, though I think indexing into [1,2.5,5] with the modded value
is cute.
awwaid suggested an improvement:
map { 10**(int $_ / 3 +2) * 2**($_ % 3 -2) } -1..9
Which hurt my head for a while: it comes from the realization that the sequence is actually
10 100 100 100 1000 1000 / 1 4 2 1 4 2
sub your_seq {
my $n = shift;
return 10 unless $n;
my @prev = your_seq($n-1);
return (@prev, $prev[-1] * ($n % 3 == 1 ? 2.5 : 2));
}
That has a rather odd recursion style: turning it into tail-recursive style, and then
eliminating the recursion using the techniques from
Higher Order Perl
sub cycle {
my @list = @_;
my @curr = @list;
return sub {
@curr = @list unless @curr;
return shift @curr;
};
}
Now we can create a list of functions that multiply by 2.5, 2, 2:
cycle([ map { times($_) } @multipliers ])
Where "times" is a function that given one multiplier, returns a function that
multiplies by that number. That is to say, it's the * operator "curried".
And by great coincidence, I just uploaded
Sub::Curried to CPAN, so we'll
use that:
curry times ($x,$y) { $x * $y }
We'll use the "curry" declarator for the rest of this example, largely because of the
automatic argument unpacking magic (I love Matt Trout's
Devel::Declare).
Now that we have a sequence, we need to write something similar to Haskell's scanr,
that repeatedly applies a transformation, returning a list of the intermediate values.
curry scan_iterator ($it, $start) {
my $next = $start;
return sub {
my $ret = $next;
$next = $it->()->($next); # prepare next value;
return $ret;
};
};
And as Perl doesn't like infinite calculations, we may as well transform a slice of this
sequences into an array:
curry iterator_to_array ($it, $count) {
return map { $it->() } 1..$count;
};
At which point we can put the whole thing together like so:
say for iterator_to_array(
scan_iterator(
mk_seq( [2.5, 2, 2] )
)->(10) # start value
)->(12); # number of iterations
I've uploaded the final source code as
an example for Sub::Curried.
Elegant? Overcomplicated? You decide!
Update:
Notice how (times) with no arguments is equivalent to a function reference, due to the autocurrying!say for take 12 => scanl(times)->(10 => cycle [2.5, 2, 2] );
A couple of interesting comments to my Five things I hate about Perl. Quicksilver pointed out that I'd missed the difference between arrays and lists. Yup, that's pretty subtle, and of course it's bitten me a few times (though oddly enough, I don't have that strong a dislike of it). Luqui on the other hand pointed out that Perl is so much more fun if you do take the plunge and use language-mutating modules, irrespective of the fact that they're not standard. I do agree, though it can sometimes be difficult getting to use these modules for work, as everyone else has to buy in to the benefits and (perceived or real) risks (learning curve, stability, speed, etc.).
So here's an example of something that I'd forgotten I hated until I banged my head against it in work's codebase: AUTOLOAD.
AUTOLOAD like other languages' "method-missing" feature, allows you to dynamically respond to a method invocation without having explicitly defined the method. So, for example, someone might call get_name on an object, and the accessor for the 'name' field will be automatically be generated.
Actually, that sounds pretty cool, no? The problems are really in the implementation.
use vars '$AUTOLOAD';
sub AUTOLOAD {
my $sub_name = $AUTOLOAD=~/(\w+)$/;
...
}
Yuck. Of course, someone has already dealt with most of the problem in a module: Ben Tilly's Class::AutoloadCAN. Using this module, you just declare a CAN sub, which may or may not return a coderef (the subroutine that will deal with the problem). Behind the scenes, overriding of the standard 'can' meta-method and an auto-generate AUTOLOAD will automagically do the right thing. Yay!
The syntax isn't that pleasant though. If we want to handle multiple autoloaded subs, we have to stick them all into this CAN routine. I'd much rather do something like:
sub foo :handles(/^foo_(.*)/) {
print "Fooing $1";
}
sub bar :handles(/^bar_(.*)/) {
print "Bar'ing $1";
}
So I thought, let's use Attribute::Handlers, which lets us define these handlers. But I don't really like Perl's
attributes feature, and to be honest, I'm not keen on the redunancy of naming a sub and then the
regex that it handles.
I'd rather have some syntax like:
autosub (get_(.*)) {
...
}
and of course that suggests Matt Trout's beautiful
Devel::Declare.
And it's surprisingly simple* to knock up a prototype AutoSub module which implements this. From the accompanying test.pl:
autosub (^take_(.*)) {
my($what, @args) = @_;
return "Took a $what";
};
autosub (^get_([^_]+)_(.*)) {
my($adj, $noun, @args) = @_;
return "Got a $adj $noun";
};
autosub (^do_the_.*$) {
my ($what, @args) = @_;
return join "," => $what, @args;
};
* Where "surprisingly simple" glosses over a couple of points, noted here briefly for reference:
Osfameron's blog on Haskell, Perl programming, stuff.