Implementar seu próprio dialeto Lisp é um exercício legal! E é divertido ver muitos avisos de recursão profunda do ” que-runs-si executar-a-lisp-que-é escrito-em-lisp ” teste .
Alguns exemplos do shell PerLisp
(bind to-ten '(1 2 3 4 5 6 7 8 9 10))
(1 2 3 4 5 6 7 8 9 10)
(define (add-1 x) (+ x 1))
Function: (x) -> (+ x 1)
(map add-1 to-ten)
(2 3 4 5 6 7 8 9 10 11)
(filter (lambda (n) (= (% n 2) 0)) to-ten)
(2 4 6 8 10)
(define (sum l) (reduce + l 0))
Function: (l) -> (reduce + l 0)
(sum '(1 -1))
0
(sum to-ten)
55
(define (product l) (reduce * l 1))
Function: (l) -> (reduce * l 1)
(product '(6 7))
42
(product to-ten)
3628800
Partes de codigo
O eval
método da minha classe PerLisp. Eu acho que é muito simples: ele transforma uma string de entrada em um fluxo de tokens que serão analisados em uma lista de expressões. Todas as expressões devem implementar um eval
método que pode depender do contexto circundante. O valor de retorno do método é a lista de valores resultante ou (no contexto escalar) o primeiro valor:
sub eval {
my ($self, $string) = @_;
# lex
my $token_stream = $self->lexer->lex($string);
# parse
my @exprs = $self->parser->parse($token_stream);
# eval
my @values = map { $_->eval($self->context) } @exprs;
# return
return wantarray ? @values : shift @values;
}
Uma expressão de símbolo, por exemplo, procura-se no contexto fornecido:
sub eval {
my ($self, $context) = @_;
return $context->get($self->name);
}