やさしい Lisp の作り方 by Java and by C#を参考に書いてみる。リストの構成にはシンボルが出てこない。
名前を付けるということがちょっと分かったような気がした。
シンボルは Lisp の最も重要なデータタイプの一つです。「記号」とか単に「名前」または「識別子」とも呼ばれていました。
シンボルは (1) 1 個以上の値を持つことができる、(2) シンボル名により唯一性が保障されます。(2) の唯一性とは同じ名前のシンボルは同じであることを表しています。もっと正確に言えば、同じ名前のシンボルは、ある等価関数によって必ず T を返す、つまり等価であることを保障します。
とりあえず、動くとこを見たかったので、色々端折ってる。
Atom
package Moosp::Atom;
use Moose;
__PACKAGE__->meta->make_immutable;
no Moose;
1; # End of Moosp::Atom
Number
package Moosp::Number;
use Moose;
extends 'Moosp::Atom';
sub str {}
no Moose;
1; # End of Moosp::Number
Integer
package Moosp::Integer;
use Moose;
extends 'Moosp::Number';
with 'Moosp::Sexp';
has 'value' => (is => 'rw',isa => 'Int');
sub add {
my ($self, $i) = @_;
my $new_value = $self->value + $i->value;
__PACKAGE__->new({value => $new_value});
}
sub subt {
my ($self, $i) = @_;
my $new_value = $self->value - $i->value;
__PACKAGE__->new({value => $new_value});
}
sub mul {
my ($self, $i) = @_;
my $new_value = $self->value * $i->value;
__PACKAGE__->new({value => $new_value});
}
sub div {
my ($self, $i) = @_;
my $new_value = int($self->value / $i->value);
__PACKAGE__->new({value => $new_value});
}
sub ge {
my ($self, $i) = @_;
if ($self->value >= $i->value){
return Moosp::T->new();
}
else {
return Moosp::Nil->new();
}
}
sub str {
my $self = shift;
return $self->value;
}
__PACKAGE__->meta->make_immutable;
no Moose;
1; # End of Moosp::Integer
Cell
package Moosp::Cell;
use Moosp::Nil;
use Moose;
has 'car' => (
is => 'rw',
default => sub{ Moosp::Nil->instance }
);
has 'cdr' => (
is => 'rw',
default => sub { Moosp::Nil->instance }
);
__PACKAGE__->meta->make_immutable;
no Moose;
1;
List
package Moosp::List;
use Moose;
use Moosp::Nil;
extends 'Moosp::Cell';
sub BUILD {
my ($self, $car, $cdr) = @_;
$self->car(Moosp::Nil->instance);
$self->cdr(Moosp::Nil->instance);
return $self;
}
sub serialize {
my $self = shift;
my $str = "(";
$str .= $self->car->serialize;
if (ref($self->cdr) eq 'Moosp::Nil') {
$str .= ")";
}
elsif (ref($self->cdr) eq 'Moosp::List') {
$str .= " " . $self->cdr->serialize . ")";
}
else {
$str .= " . " . $self->cdr->serialize . ")";
}
return $str;
}
1; # End of Moosp::List
test
my $int3 = Moosp::Integer->new(value => 3);
my $int5 = Moosp::Integer->new(value => 5);
my $list = Moosp::List->new();
$list->car($int3);
$list->cdr($int5); # (3 . 5)
my $list2 = Moosp::List->new();
$list2->car($int3);
$list2->cdr($list); # (3 (3 . 5))
print $list2->cdr->car->value # cadr -> 3