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], ">+<"].
0 commentários:
Enviar um comentário