define
, let
e set!
, tirando proveito das regras de escopo.Supondo o seguinte caso: tenho um arquivo (uma biblioteca) que será usado por outras pessoas e embutido em outros códigos. Neste arquivo estarão alguns procedimentos que serão parte da API e procedimentos auxiliares úteis para o desenvolvimento do próprio código desta biblioteca. Mesmo sem usar um sistema de módulos, é possível minimizar a poluição do espaço de nomes que seria causado pelos procedimentos auxiliares com a seguinte estratégia:
(define proc-api-1 #f)
(define proc-api-2 #f)
(let ()
(define (proc-aux arg) (codigo))
(set! proc-api-1 (lambda () (proc-aux 3)))
(set! proc-api-2 (lambda () (proc-aux (proc-aux 1000)))))
No exemplo temos dois símbolos visíveis no escopo mais amplo (toplevel) deste arquivo :
proc-api-1
e proc-api-2
. A outra definição proc-aux
, que é útil para a implementação dos procedimentos da API, fica no escopo do bloco (let () ...)
, ou seja, não é visível do toplevel. Dentro do bloco (let () ...)
, então, fazemos a atribuição do código dos procedimentos da API às variáveis definidas no toplevel.Um exemplo mais prático (mas não menos besta):
(define ul #f)
(define li #f)
(define p #f)
(let ()
(define cria-tag
(lambda (nome)
(let ((nome (symbol->string nome)))
(lambda args
(string-append "<" nome ">"
(string-intersperse args "")
"</" nome ">"))))
(set! ul (cria-tag 'ul))
(set! li (cria-tag 'li))
(set! p (cria-tag 'p)))
Executando isso no REPL, podemos ver o efeito da estratégia usada:
$ csi -n
CHICKEN
(c)2008 The Chicken Team
(c)2000-2007 Felix L. Winkelmann
Version 3.2.0 - linux-unix-gnu-x86 [ manyargs dload ptables applyhook ]
SVN rev. 10664 compiled 2008-05-08 on ze-dureza (Linux)
#;1> (load "cria-tag.scm")
; loading cria-tag.scm ...
#;2> p
#<procedure (? . args)>
#;3> li
#<procedure (? . args)>
#;4> ul
#<procedure (? . args)>
#;5> cria-tag
Error: unbound variable: cria-tag
#;5> (p "nada")
"<p>nada</p>"
Conforme esperado, a definição de
cria-tag
não é visível no toplevel, mas as funções que a usam funcionam.Esta estratégia é bastante usada na implementação do sistema Chicken, por exemplo.
2 comentários:
bah! que gambi mais suja só para não implementarem namespaces na linguagem :(
namespaces são ortogonais ao paradigma!
Alô Ron,
O fato de existirem gambis sujas não quer dizer que não existam soluções "ortogonais ao paradigma": http://www.r6rs.org/final/html/r6rs/r6rs-Z-H-10.html#node_chap_7
Várias implementações de Scheme disponibilizam de uma forma ou de outra facilidades para deliminação de espaços de nomes. A R6RS especifica uma.
Nunca tentei, mas imagino que seja possível fazer um gerador de espaços de nomes com uma macro que quando expandida gere um código semelhante ao da gambi suja (o que, dependendo do nível de abstração de que se trata, pode não ser tão suja).
Postar um comentário