2010-12-09

read :: Read a => String ->

(continuando…)

Show foi fácil, então e Read?

Agora que já instanciamos Show, vamos instanciar Read. Esta é mais complicada que Show, mas não é inacessível.

Em primeiro lugar, vamos inspecionar a classe Read.


> :i Read
class Read a where
readsPrec :: Int -> ReadS a
-- ... mais outras que não interessam ...
-- ... montes e montes de instâncias ...

Temos de definir uma função que recebe um inteiro e devolve um ReadS a… Ok, o que é um ReadS a?

> :i ReadS
type ReadS a = String -> [(a, String)]

Hmmm, então na realidade o que temos é:

readsPrec :: Int -> String -> [(a, String)]

Se definirmos esta função, podemos depois usar a função read para ler programas em brainfuck directamente para a nossa representação com os tipos BF e BFCommand.

read :: String -> BF
read :: String -> BFCommand

Mas que raio é que são aqueles parâmetros? Um inteiro? Uma lista de pares?

Bem, o primeiro parâmetro é um número que é chamado de “nível de prioridade”. Este parâmetro serve para podermos controlar as coisas quando temos vários operadores com prioridades diferentes entre eles. Imaginem que estamos a ler contas de somar e multiplicar para este tipo:

data Contas = Multiplicar Contas Contas
| Somar Contas Contas
| Numero Int

Ao lermos 1 + 2 * 3 era necessário que o resultado fosse Somar (Numero 1) (Multiplicar (Numero 2) (Numero 3)) e não Multiplicar (Somar (Numero 1) (Numero 2)) (Numero 3). Este primeiro parâmetro serve para definir estas prioridades.

No nosso caso, como não há prioridades em brainfuck, não necessitamos de ligar a este primeiro parâmetro.

O segundo, uma string, é fácil de perceber: é o texto para ler.

O resultado é uma lista de pares (resultado parcial, texto restante). Desta forma podemos ler o texto aos poucos e ir construindo o resultado aplicando recursivamente readsPrec no texto restante.

Este resultado é uma lista porque podem existir várias alternativas. No caso de brainfuck, a sintaxe não tem ambiguidades nenhumas, por isso o nosso readsPrec irá sempre devolver uma lista com um elemento.

Por exemplo, readsPrec 0 "->+<" deverá dar como resultado uma lista com um par (resultado de ler "-", resto da string), ou seja [(BF [DecVal], ">+<"].

(continua…)

0 commentários:

Enviar um comentário