型グロブをいまいちちゃんと理解してないっぽい

型グロブで悩むの巻

*a = sub {1+2}

が$a->()でなくて

a() # 3

なのがいまいちわからない。

$ perlsh
main[82]$ $a = 5
5
main[83]$ $b = \$a
SCALAR(0x984e018)
main[84]$ *a
*main::a
main[85]$ *a{SCALAR}
SCALAR(0x984e018)
main[86]$ ${*a{SCALAR}}
5
main[87]$ $$b
5

ということは $b = \$a = *a{SCALAR}だからリファレンスベースで考えていけばいいのかな、、、、

$ $a = [1,2,3,4]
ARRAY(0x984e048)
main[89]$ @$a
1
2
3
4
main[90]$ *b = $a
*main::b
main[91]$ @b
1
2
3
4

とこんな感じ。

実用Perlプログラミングにグロブはハッシュを使って実装されてると書いてある。

ProductName 実用Perlプログラミング
サイモン カズンズ
オライリージャパン / ¥ 3,360 (2006-03)
通常24時間以内に発送

main[92]$ $a = [1,2,3]
ARRAY(0x9989060)
main[93]$ $b = {a => 3}
HASH(0x99890c0)
main[94]$ *c = $a
*main::c
main[95]$ *c = $b
*main::c
main[96]$ @c
1
2
3
main[97]$ %c
a
3

なんかrefの型にマッチさせてハッシュっぽくしてる感じだ。

でもまだちゃんと掴みきってないナァ。あと第2版は1章に小難しい話題を入れてる割にはページが少ないのでちょっとアレ。実用Perlプログラミング的には一章100pぐらいあって充実されてるほうが嬉しい。

HOP 6章終了

Higher-Order Perl 6章は無限ストリーム。SICPの3章あたりに対応してるので、SICPのcar,cdr,consで無限ストリームを扱うあたりを読んでいれば最初のほうはサクサク読めた。特にストリームの混ぜ合わせとかが面白い。

6.5がストリームを使ってREGEXから文字列を生成するという節。ここが結構わかりにくくて数ページずつくらいしか読み進められなかった。*(0回以上の繰り返し)の表現とか最初なかなか理解できなかったので、紙に書き下したりとかした。

6.6のNewton-Raphson MethodoもSICPで既に読んでたので、比較しながら読むと楽しい。ついでにループ判定の方法を使って数値の振動を発見する方法にふれてて面白かった。Gaucheクックブック循環リストを扱うのアルゴリズム。

エラトステネスの篩のストリーム

HOPの6章は無限ストリームを扱っているのだけれど、SICPの無限ストリームの章にあるエラトステネスの篩が出てこないので書いてみた。

HOPだとcar,cdr,consがそれぞれhead,tail,nodeとなってるのでそれにあわせてある。promiseは計算を遅延させるためのクロージャ。

use strict;
use warnings;
no warnings 'recursion';

sub promise (&) { $_[0] }

sub node{
  my ($h, $t) = @_;
  [$h, $t];
}

sub head {
  my ($ls) = @_;
  $ls->[0];
}

sub tail {
  my ($ls) = @_;
  if(is_promise($ls->[1])){
    $ls->[1] = $ls->[1]->();
  }
  $ls->[1];
}

sub is_promise {
  UNIVERSAL::isa($_[0],'CODE');
}

sub drop {
  my $h = head($_[0]);
  $_[0] = tail($_[0]);
  return $h;
}

sub filter (&$) {
  my $f = shift;
  my $s = shift;
  until(! $s || $f->(head($s))){
    drop($s);
  }
  return if ! $s;
  node(head($s),promise {filter($f, tail($s))});
}

sub sieve {
  my $s = shift;
  node(head($s),
       promise {sieve(filter {$_[0] % head($s)} tail($s))});
}

sub upfrom {
  my ($m) = @_;
  node($m, promise{ upfrom($m+1)});
}

sub show {
  my ($s,$n) = @_;
  while($s && (! defined $n || $n-- > 0)){
    print head($s), $";
    $s = tail($s);
  }
  print $/;
}

my $primes = sieve(upfrom(2));
show($primes,300);

これで、素数のストリームが生成される。

ProductName 計算機プログラムの構造と解釈
ジェラルド・ジェイ サスマン,ジュリー サスマン,ハロルド エイブルソン
ピアソンエデュケーション / ¥ 4,830 (2000-02)
通常24時間以内に発送

ProductName Higher-order Perl: A Guide To Program Transformation
Mark Jason Dominus
Morgan Kaufmann Pub / ¥ 7,608 (2005-05-30)
通常24時間以内に発送

無限ストリームは楽しい

perlの grep $_, @_;

HOP6.5でなんだコレは?と。($_,@_)なんてありなのかと思ったがどうも違った。

sub test {
  my ($h, @s) = grep $_, @_;
  print "h:\t$h\n";
  print "s:\t";
  print join ",",@s,"\n";
}

test(3,undef,1,4,5);

実行結果

h:      3
s:      1,4,5,

配列の中からundefを除く、($_,@_)っていう配列ではなくて grep {$_} @_みたいな感じのgrep tipsだった。

vxでタグが入れられるようにしてみた

Voxクライアントが便利だが、タグ付けできなくてちょっと不便なので入れられるようにしてみた。それぞれのエントリみると

<category term="test" label="test" />

みたいに組めばよさそうだったので、blog.nomadscafe.jpを参考に。

my $entry = XML::Atom::Entry->new;
$entry->title($title);
my $category = XML::Atom::Category->new(Version=>1);
$category->term('life');
$category->label('life');
$entry->category($category);
$entry->content($content);

これだと、なぜかタグが反映されない。なんでかなーと調べてたらSix Apartの野良プラグインにヒントが あった。

<dc:subject xmlns:dc="http://purl.org/dc/elements/1.1/">life</dc:subject>

が正しいらしい。なので修正したら動いた。

use constant NS_DC => 'http://purl.org/dc/elements/1.1/';

...

my $entry = XML::Atom::Entry->new;
$entry->title($title);
$entry->content($content);
my @tags = split /,/, $category;
my $dc = XML::Atom::Namespace->new( dc => NS_DC );
foreach my $tag (@tags) {
  $entry->add( $dc, 'subject', $tag);
}

オプションでタグを選べるようになった

$ vx -t 英語ネタ -c english,life "fortranner の goto は \
ロードランナーの穴掘り。たまに掘った穴に埋まる"

vx (Vox用のCLI)

vox用のCLIを作った。post用のURIはこんな感じで探した。本当はhttp://www.vox.com/services/atomにGETして返ってきたXMLをパースすんのがいいんだろうけど、これはそのうちやる。今回は直接指定した。

#!/usr/bin/perl

use XML::Atom::Client;
use XML::Atom::Entry;
use Getopt::Long;

# --- configure --- #
my $user = vox_user;
my $password = vox_passwd;
my $title = "'(my memo)";
my $PostURI = posturl;

# --- main --- #

GetOptions ("title=s"   => \$title);
my $content = shift @ARGV;

die "content not found\n" unless $content;

my $api = XML::Atom::Client->new;
$api->username($user);
$api->password($password);

my $entry = XML::Atom::Entry->new;
$entry->title($title);
$entry->content($content);
my $EditURI = $api->createEntry($PostURI, $entry);
print $api->errstr if $api->errstr;

これをvxって名前で保存しておく。以下使用例

$ vx "なんか思いついたことを書くとよさげ"

タイトルを変えたいときには

$ vx -t todo "ビリーでダイエット"

とか。

AtompubでVox用のクライアントを作ろうとしたが

自分のVox用にCLIが欲しくて、Atompubでつくろっかなと思ったので。

use Atompub::Client;
my $service_uri = 'http://kzfm.vox.com/library/posts/atom.xml';
my $client = Atompub::Client->new;
$client->username('xxx@gmail.com');
$client->password('mokyumokyu');

my $service = $client->getService( $service_uri );

さてこれがエラー。

$ perl atomc.pl
Bad Content-Type: text/xml at /usr/lib/perl5/site_perl/5.8.8/Atompub/Client.pm line 220.
Can't call method "collections" on an undefined value at atomc.pl line 14.

Atompub::MediaTypeあたりを触ればいいんだろうか?エンドポイント間違えてるだけだったりして、、、、

ちょっと興味があるのでソースを読んでみる。あとdraft-ietf-atompub-protocol-17.txtも併せて読む

追記 07.09.18

色々ボケてた。

rsd.xmlに記述されているAtomのAPIにGETしないといけない。

$ wget --http-user=user --http-passwd=XXX \
http://www.vox.com/services/atom

で戻ってきたxmlの中見てservice.postにPOST

ここへのPOSTはXML::Atom::ClientでもAtompub::ClientでもどちらでもOK

HOP 5章終了

三連休は読みまくった。あと、家族が留守のため集中できたので、再帰をイテレータに変えるという章を読み終えた。

ProductName Higher-order Perl: A Guide To Program Transformation
Mark Jason Dominus
Morgan Kaufmann Pub / ¥ 7,625 (2005-05-30)
通常24時間以内に発送

この章は後半が大変面白い。末尾再帰とかの話で末尾再帰にできればwhile,until,forみたいなループにすることができるって話題から、最後にフィボナッチ数みたいに再帰が複数ある場合に再帰を排除するっていうネタで10pageくらい割いてる。

特にフィボナッチから再帰を剥ぎ取る部分が非常に面白かった。再帰をperlの内部スタック表現を配列使って明示的に触れるようにすることで排除するヨっていう流れをステップバイステップで進んでいくんだけど、ついていくのに非常に苦労して、時には紙に書いたり、時には何度も読み返したり、そして時には犬の散歩をしたりと結局半日費やしたが、読み終えてそれだけの価値があったと思う。

次、無限ストリーム。楽しみな章。

HOP 4章終了

Higher-Order Perlの4章は100pageに及ぶイテレータの章。

ProductName Higher-order Perl: A Guide To Program Transformation
Mark Jason Dominus
Morgan Kaufmann Pub / ¥ 7,625 (2005-05-30)
通常24時間以内に発送

4.3.1のpermutationのところがかなり面白い。組み合わせをシーケンスにするとことか基底を列ごとに変える部分とか。4.3.2はゲノム配列の組み合わせ問題で懐かしさ満開、といっても僕はそのころはEMBOSSとかに頼っていたのであまりそういう問題に関して深く考えたことなかったな(既にツールとして色々あったし、、、)

4.4でイテレータ版のmapとgrep。これは色々と楽しそう。Iterator::Utilというモジュールがある。

後半は読み物色が強くなってて、イテレータの終わりとSQLでいうNULLにあたるものをどう区別していくかみたいな。一番最後にweb spideringの例が示してあってigrepとimapがかなりいい感じ。

HOP 4.5.7

Higher-Order Perl

hash,arrayのほかにクロージャもblessできる。

Perl におけるオブジェクト指向

Perl のオブジェクトを作るときは、まず組み込みのデータ型から適当なものを選びます。普通はハッシュを使うことが多いと思いますが、配列やクロージャ(無名サブルーチン)もオブジェクトに出来ます。

ProductName Higher-order Perl: A Guide To Program Transformation
Mark Jason Dominus
Morgan Kaufmann Pub / ¥ 7,625 (2005-05-30)
通常24時間以内に発送

いくつかのアクションを持つイテレータを用意したとき

$it->('next');

とか書かないといけないところを

sub Iter::next {$_[0]->('next')}

というような関数を用意する。更に、イテレータを受け取ってblessして返す関数を適用。

sub Iterator (&) { bless $_[0] => 'Iter'}

そうすると、

$it->next

というようなメソッド風呼び出しが行え、一種の構文糖衣的な使い方と考えておけばよいのだろう。