MooseでLispを実装してみる(Reader)

やさしい Lisp の作り方 by Java and by C#を参考に書いてみる。

readerは文字列(strings)と今読んでいる位置(index)と現在読んでいる文字の値(char)の属性を用意してあって、一文字読み進めてインデックスを一つ進めるget_charと一文字読み進めるけどインデックス値は進めないという先読み機能のnext_charというメソッドで移動していく。

先読みメソッドを用意するよりはインデックス値を一つ巻き戻すメソッドを用意しておいて、必要に応じてインデックス値を減らすという実装のほうだとcharアトリビュートを用意しておく必要はないかなと思った。

よくわからなくなってきたのでもう一度きちんと見直すかも

package Moosp::Reader;

use Moose;
use Moosp::Nil;
use Moosp::T;
use Moosp::List;
use Moosp::Integer;
use Moosp::Symbol;
use Moosp::Env;

has env => ( is => 'rw', isa => 'Moosp::Env', default => sub { Moosp::Env->new });
has index => (is => 'rw', isa => 'Int', default => 0 );
has strings => (is => 'rw', isa => 'Str');
has char => (is => 'rw', isa => 'Str');

sub get_char {
  my $self = shift;
  my $index = $self->index;
  $self->char(substr($self->strings,$index,1));
  $self->index($index + 1);
  return $self->char;
}

sub next_char {
  my $self = shift;
  $self->char(substr($self->strings,$self->index,1));
  return $self->char;
}

sub getSexpPrepare {
  my $self = shift;
  $self->getSexpPrepareString(@_);
}

sub readFromString {
  my ($self, $input) = @_;
  $self->getSexpPrepareString($input);
  $self->getSexp;
}

sub getSexpPrepareString {
  my ($self, $input) = @_;
  $self->strings($input);
}

sub getSexp {
  my $self = shift;
  while (my $ch = $self->get_char()) {
    if    ($ch eq '(')  { return $self->makeList(); }
    elsif ($ch eq '\\') { return $self->makeQuote(); }
    elsif ($ch eq '-')  { return $self->makeMinusNumber(); }
    else  {
      if ($ch =~ /\s/)  { last; }
      if ($ch =~ /\d/)   { return $self->makeNumber($ch); }
      return $self->makeSymbol($ch);
    }
  }
  return Moosp::Nil->instance;
}

sub makeList {
  my $self = shift;

  my $top = Moosp::List->new();
  my $list = $top;
  my $ch;
  while(1) {
    $list->car($self->getSexp());
    $ch =  $self->char;
    last if ($ch eq ')');
    return Moosp::Nil->instance if ($ch eq '');
    if ($self->next_char eq '.') {
      $ch = $self->get_char();
      $ch = $self->get_char();
      $list->cdr($self->getSexp());
      return $top;
    }
    $list->cdr(Moosp::List->new());
    $list = $list->cdr();
  }
  $ch = $self->get_char();
  return $top;
}

sub makeNumber {
  my ($self, $str) = @_;
  while (my $ch = $self->get_char()) {
    last if $ch eq '(' || $ch eq ')';
    last if $ch =~ /\s/;
    unless ($ch =~ /\d/) {
      $self->index($self->index - 1);
      return $self->makeSymbolInternal($str);
    }
    $str .= $ch;
  }
  return Moosp::Integer->new({value => $str});
}

sub makeSymbol {
  my ($self, $ch) = @_;
  return $self->makeSymbolInternal($ch);
}

sub makeSymbolInternal {
  my ($self, $str) = @_;
  while (my $ch = $self->get_char()) {
    last if $ch eq '(' || $ch eq ')';
    last if $ch =~ /\s/;
    $str .= $ch;
  }
  $str = uc $str;
  return Moosp::T->instance if ($str eq 'T');
  return Moosp::Nil->instance if ($str eq "NIL");

  my $sym = $self->env->symbol->{$str};
  return $self->env->set_symbol(Moosp::Symbol->new(name => $str)) unless defined($sym);
  return $sym;
}

sub makeMinusNumber {
  my $self = shift;
  my $nch = $self->next_char();
  return $self->makeSymbolInternal("-") unless $nch =~ /\d/;
  return $self->makeNumber("-");
}

sub makeQuote {
  my $self = shift;
  my $top = Moosp::List->new();
  my $list = $top;
  $list->car($self->env->symbol->{"QUOTE"});
  $list->cdr(Moosp::List->new());
  $list = $list->cdr();
  $self->get_char();
  $list->car($self->getSexp());
  return $top;
}

1; # End of Moosp::Reader

Readerが出来るとそれっぽくなってきた感じがする。

鎮国之山本醸造(火入れ)

うちの近所だと、日曜日に開いているまともな酒屋が少ないので、どんなに疲れていても土曜日に酒屋詣でをするのだけど、先週はなぜかお参りできなかったので、仕方なく吉原のあたりをぶらぶらしてたら、アドニスの近くに酒屋を見つけたので入ってみた。

品揃え的には七賢とかそんな感じだったのだけど、高砂のとこでやっている鎮国之山があったので購入。まぁ知らないところの冷蔵管理の酒はちょっとヘジテートするので、火入れで。

1240144791

ラベルはなし。高砂にしてはすっきり目でなかなかうまい。あとは酒屋のヒトとはよく話すようにしている。純米はないのかとか一升はないのかとか、冷蔵庫みれば分かるじゃん的な質問をジャブ的にかますと、色々教えてくれたりするので楽しい。

自分で失敗を自覚するまで納得できない人

自分で失敗を自覚するまで納得できない人は失敗が確定するまで、失敗が近づけば近づくほど指数関数的に頑張り(そして周りにもがんばりを強要し)、精神論をまき散らしつつ周りを巻き込み疲弊させ最終的に集団心中するようなタイプが多いような気がする。

しかし、本人は頑張ったという達成感で一杯なので、次もめげずに同じことを繰り返すのだ。

屍を超えていくのではなく、屍を再生産しようとするそのスタイルは僕は好きではなかったりする。

3年半ぶりくらいのセロリ畑

娘がオムライスを食べたいと言い出したので、セロリ畑へ行くことにした。記憶(というかデータベース)を辿ると実に三年半ぶりだった。

1240144795

娘はビーフのオムライス。僕は辛さ4のカツカレー。カレーはやはり甘さと酸味が強いのでこのくらい辛くても良い感じ。もう一段辛くてもいいかな。あと卓上のスパイスミルを振りかけることで香りが向上していい。次はナンのセットにしたいとこ。

1240144802 1240144809

帰りに近くにある通称新幹線の公園に行った。僕だけ初めてだったがなかなかよさげ。鉄道のレールは30Kg/mあってかなり重いというまめ知識を仕入れた。

1240144799

鉄道鉄琴がかなり面白くて、娘と一緒になって叩きまくった。

1240144806

あと、機械と自然のフュージョンっぷりがなかなかよろしかった。

Use R

シリーズ物だったのね、知らんかった。

ProductName Analysis of Integrated and Cointegrated Time Series with R (Use R!)
Bernhard Pfaff
Springer New York / 7631円 ( 2008-08-11 )


ProductName Data Manipulation with R (Use R!)
Phil Spector
Springer / 7861円 ( 2008-03-19 )


ProductName Bayesian Computation with R (Use R)
Jim Albert
Springer-Verlag / ?円 ( 2007-07 )


ProductName Applied Spatial Data Analysis with R (Use R!)
Roger S. Bivand
Springer / 8586円 ( 2008-08-14 )


ProductName Applied Statistical Genetics with R: For Population-based Association Studies (Use R!)
Andrea S. Foulkes
Springer New York / 5834円 ( 2009-04-17 )


ProductName Analysis of Phylogenetics And Evolution With R (Use R)
Emmanuel Paradis
Springer New York / 6473円 ( 2006-07-28 )


ProductName Nonlinear Regression with R (Use R!)
Christian Ritz
Springer / 7631円 ( 2008-11-21 )


ProductName Wavelet Methods in Statistics with R (Use R!)
Guy Nason
Springer / 8089円 ( 2008-08-11 )


PDCAと陰陽

会社で資料をつくる時にはplan-do-check-actなPDCAサイクルを引き合いに出すことが多いのだけど、本当は陰陽マークのほうが好みだ。

yinyang

do-checkは陽でact-planは陰

陽の部分は効率化の対象になりやすく陳腐化しやすいけど、陰の部分は内に向かい経験により高いところを目指せる。

そしてヒトはdarkcoreに向かう

ProductName Warlords Rising
Future Phrophecies
Beatservice / ¥ 2,422 (2005-11-29)


Vox用のクライアント

Config::Pitエディタが立ち上がるように変更した。

サービスのURIを知るためにwgetしたらつながらなくてあせったが--auth-no-challengeオプションを入れて解決

#!/opt/local/bin/perl

use XML::Atom::Client;
use XML::Atom::Entry;
use constant NS_DC => 'http://purl.org/dc/elements/1.1/';
use File::Temp;
use File::Slurp;
use Path::Class;
use Config::Pit;

my $vox = "kzfm.vox.com";
my $title = "";
my $content = "";
my $category = "life";

my $config = pit_get($vox, require => {
        "username" => "your username on vox",
        "password" => "your password on vox",
        "postURI"  => "your potURI"
                       });


my $f = File::Temp->new();
close $f;
my $t = file($f->filename)->stat->mtime;
system $ENV{EDITOR}, $f->filename;
if ($t == file($f->filename)->stat->mtime) {
 print STDERR "No changes.";
} else {
 my @lines = read_file($f->filename);
 $title = shift @lines;
 $content = join "", @lines
}

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

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

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);
}

my $EditURI = $api->createEntry($config->{postURI}, $entry);
print $api->errstr if $api->errstr;

pybelでRECAP

pybelでのRECAP実装が投稿されたもようだが、実際はopenbabelバインディングでの実装なのかな。

あとで試す。

シンボル、オブジェクト、シニフィエ、シニフィアン

自分で実装しながら、オブジェクトとシンボルはシニフィエ、シニフィアンの関係みたいだなぁと思ってたわけだが、既にそういう話はあった

シニフィアンのほうをいじくればesotericなlispが出来るのであろう。それは括弧でくくらなくても良くて、例えば二次元平面に描画された円で囲まれた図形がS式となってもよいのかも。その場合泡のような絵がlispプログラムになるのか。

ProductName Rubyで作る奇妙なプログラミング言語 ~Esoteric Language~
原 悠
毎日コミュニケーションズ / ¥ 2,814 ()
在庫あり。

perlでread-eval-print-loop

クォートされたS式を受け取って文字列を返すものをつくってみた。

use Term::ReadLine;
my $term = new Term::ReadLine 'Simple LISP REPL';
my $prompt = "CL-USER> ";
my $OUT = $term->OUT || \*STDOUT;

while ( defined ($_ = $term->readline($prompt)) ) {
  my $res = $_;
  warn $@ if $@;
  $res =~ s/^\'//;
  print $OUT $res, "\n" unless $@;
}

実行

$ perl s.pl
CL-USER> '(+ 1 2)
(+ 1 2)
CL-USER>

という手抜き。

だが、Readerを実装して処理させれば良いのであろう。