segunda-feira, 26 de abril de 2010

Awful scripts

Uma dica rápida para executar aplicações web em awful como scripts em sistemas Unix[-compatíveis]: usando a linha com shebang.

Dessa forma, basta executar o arquivo com a aplicação web como se fosse um arquivo executável qualquer:
$ cat hello-world.scm
#! /usr/bin/awful

(use awful)

(define-page (main-page-path)
(lambda ()
"Hello, world!"))

$ ./hello-word.scm

sexta-feira, 16 de abril de 2010

Sintaxe para definição de "curried procedures"

A definição de curried procedures é bastante usual em Scheme. Consiste em fazer com que o valor produzido por um procedimento seja outro procedimento.

Abaixo está um exemplo de um criador de objetos que respondem a mensagens:
(define (make-obj)
(lambda (message)
(case message
((hello) "Hello!")
((bye) "Bye bye!")
(else (error "Unknown message.")))))


O código acima já está com uma sintaxe simplificada para definições de procedimentos. A forma mais longa seria:
(define make-obj
(lambda ()
(lambda (message)
(case message
((hello) "Hello!")
((bye) "Bye bye!")
(else (error "Unknown message."))))))


Não está na especificação da linguagem, mas algumas implementações oferecem a possibilidade de usar uma sintaxe mais simplificada para a definição de curried procedures:
(define ((make-obj) message)
(case message
((hello) "Hello!")
((bye) "Bye bye!")
(else (error "Unknown message."))))


Das implementações em que testei, Chicken, Guile, MIT Scheme e PLT admitem essa sintaxe para definição de curried procedures. Ypsilon e Gambit não admitem.

quinta-feira, 15 de abril de 2010

Documentação de Chicken com chicken-doc

chicken-doc é uma extensão do sistema Chicken para pesquisa e navegação na documentação do compilador e das extensões através da linha de comando.

É bem parecida com uma extensão que eu havia feito há uns anos: man. Na época da extensão man, a documentação de Chicken era no formato textinfo. man, então, fazia o parsing do arquivo texinfo e gerava um arquivo com expressões simbólicas de fácil pesquisa em Scheme. Depois da adoção de wiki para a documentação do compilador, a extensão man caiu em desuso.

chicken-doc, diferentemente da extensão man, faz o parsing de arquivos fonte do wiki, incluindo a documentação das extensões, R5RS e algumas SRFIs! Hoje foi lançada a versão 0.3.2 com a funcionalidade de pesquisa na documentação.

O uso de chicken-doc depende da geração da base de dados onde serão feitas as pesquisas. Para gerar a base de dados, é necessária a extensão chicken-doc-admin. Em http://chicken.wiki.br/eggref/4/chicken-doc-admin#quick-start há um passo-a-passo sobre como gerar a base.

Após gerada a base, pode-se usar a ferramenta de linha de comando chicken-doc:


$ chicken-doc
usage: chicken-doc -s|-c|-i path
chicken-doc -f id
chicken-doc -m re
chicken-doc id | path
-s path Show signature
-c path Show table of contents (child IDs)
-i path Show documentation
-f id Show all matching paths for ID
where ID is a single identifier and PATH is zero or
more IDs comprising a path from the documentation root,
separated by spaces or the # character.

-m re Show all matching paths for RE
where RE is a POSIX regular expression. Similar to -f.

When no option is given, guess the user's intent. With
a single ID, find the ID (as with -f) and show its
documentation (as with -i) or show all matching paths
if multiple matches exist. If more than one ID is
provided, show documentation on the path (as with -i).

Examples:
-f open/rdonly # Show matches for open/rdonly
-s posix open/rdonly # Show signature of open/rdonly in Unit posix
-s 9p open/rdonly # Show signature of open/rdonly in 9p egg
-i 9p#open/rdonly # Show documentation for same
-c posix # Show TOC for Unit posix
-c # Show toplevel TOC
-m call- # Show identifiers containing call-
-m -file$ # Show identifiers ending in -file
use # Show doc for "use" in chicken core
posix # Show doc for Unit posix
open/rdonly # Show matches for open/rdonly
posix open/rdonly # Show doc for open/rdonly in Unit posix


Alguns exemplos de uso:


$ chicken-doc reverse
path: (scheme reverse)

-- procedure: (reverse list)

Returns a newly allocated list consisting of the elements of list in
reverse order.

(reverse '(a b c)) ===> (c b a)
(reverse '(a (b c) d (e (f))))
===> ((e (f)) d (b c) a)


A primeira linha indica o "caminho" para o símbolo procurado. O primeiro símbolo do caminho pode ser scheme (indicando que é o símbolo é um componente da especificação da linguagem), o nome de uma unit de Chicken, uma SRFI ou uma extensão. É possível que ele possa ser encontrado em mais de um módulo. Neste caso, chicken-doc apresenta uma lista de opções:


$ chicken-doc enable-db
Found 3 matches:
(awful-sql-de-lite enable-db) (enable-db)
(awful-sqlite3 enable-db) (enable-db)
(awful-postgresql enable-db) (enable-db)


$ chicken-doc awful-postgresql enable-db

-- procedure: (enable-db)

Enable Postgresql support for awful
(http://chicken.wiki.br/eggref/4/awful). This procedure basically sets
up awful to use the connection, disconnection, query and query escaping
procedures for Postgresql databases.


Com a versão lançada hoje, é possivel pesquisar na base de identificadores de procedimentos, macros e parâmetros. Exemplos:


$ chicken-doc -m '^string->'
(library string->blob) (string->blob STRING)
(byte-blob string->byte-blob) (string->byte-blob STRING) => BYTE-BLOB
(sxml-transforms string->goodHTML) (string->goodHTML html)
(library string->keyword) (string->keyword STRING)
(scheme string->list) (string->list string)
(scheme string->number) (string->number string radix)
(scheme string->symbol) (string->symbol string)
(posix string->time) (string->time TIME [FORMAT])
(library string->uninterned-symbol) (string->uninterned-symbol STRING)


O argumento para o parâmetro -m é uma expressão regular.

Algumas das funcionalidades de chicken-doc podem também ser usadas no REPL:


$ csi

CHICKEN
(c)2008-2010 The Chicken Team
(c)2000-2007 Felix L. Winkelmann
Version 4.4.4
linux-unix-gnu-x86 [ manyargs dload ptables ]
compiled 2010-03-30 on dellito (Linux)

; loading ./.csirc ...
csi> (use chicken-doc)
csi> ,doc string-intersperse
path: (data-structures string-intersperse)

-- procedure: (string-intersperse LIST [STRING])

Returns a string that contains all strings in `LIST` concatenated together.
`STRING` is placed between each concatenated string and defaults to `" "`.

(string-intersperse '("one" "two") "three")

is equivalent to

(apply string-append (intersperse '("one" "two") "three"))

csi> ,wtf concatenate
(srfi-1 concatenate) (concatenate list-of-lists) -> value
(srfi-1 concatenate!) (concatenate! list-of-lists) -> value
(ports make-concatenated-port) (make-concatenated-port PORT1 PORT2 ...)


O comando ,doc mostra a documentação do símbolo dado como argumento. O comando ,wtf (de where to find ;-)) é equivalente à opção de linha de comando -m de chicken-doc.

Uma opção interessante para uso de chicken-doc é associar uma tecla de atalho para executá-lo no emacs. Em http://chicken.wiki.br/eggref/4/chicken-doc há dicas sobre como fazer isso.