Percursos
/
Factor
Factor
/
Exercícios
/
Fita do Telegrafista
Fita do Telegrafista

Fita do Telegrafista

Exercício de aprendizagem

Introdução

Já usaste streams em channel-chatter e descartaste-os em boatswains-bilge. Este exercício é o teu primeiro stream personalizado: uma classe que implementa o protocolo, para que o mesmo código with-input-stream / read1 / stream-read1 que funcionava num <string-reader> funcione no teu.

Mixins: a outra metade da hierarquia de classes

Já conheces TUPLE: child < parent … de dragons-descendants: uma hierarquia de herança simples, em que os slots passam de cima para baixo. O Factor tem uma segunda forma de estender o grafo de classes: os mixins abertos. Um MIXIN: m declara uma classe sem slots, à qual outras classes se podem juntar mais tarde com INSTANCE: c m. A associação é muitos-para-muitos: uma classe pode ser instância de tantos mixins quantos quiser.

O protocolo dos streams usa dois mixins para assinalar que metade da interface uma classe implementa:

INSTANCE: my-stream input-stream    ! readable
INSTANCE: my-stream output-stream   ! writable

Um stream pode ser um, o outro, ou ambos. Os métodos genéricos de input-stream (ou output-stream) são então despachados para qualquer classe que se tenha juntado ao mixin. É assim que o read1, o stream-contents, o with-input-stream, etc. que tens à disposição encontram o caminho até à tua classe.

Os mixins são abertos: podes acrescentar um novo membro depois de o mixin ser declarado, até num vocabulário diferente. É este o contraste com TUPLE: < parent, em que a relação fica fixada quando a subclasse é declarada.

Os genéricos do protocolo

Os genéricos do protocolo estão em io:

stream-read1         ( stream -- elt/f )
stream-read          ( n stream -- seq/f )
stream-read-unsafe   ( n buf stream -- count )
stream-write1        ( elt stream -- )
stream-write         ( seq stream -- )
stream-flush         ( stream -- )
stream-element-type  ( stream -- type )

O stream-read1 devolve o byte seguinte (ou f no fim do stream); o stream-write1 escreve um. O stream-read-unsafe é a leitura em lote de mais baixo nível que a maioria dos streams de entrada disponibiliza; o stream-read é construído sobre ele e trata da alocação. O stream-element-type indica se o stream trabalha com bytes (+byte+) ou com carateres (+character+); quando envolves outro stream, a implementação mais simples limita-se a delegar no stream subjacente.

A limpeza vem de destructors

Os streams são descartáveis: um stream personalizado estende disposable e implementa dispose*. É esse o framework de boatswains-bilge, aplicado a uma classe de stream:

TUPLE: my-stream < disposable underlying ;

: <my-stream> ( underlying -- s )
    my-stream new-disposable swap >>underlying ;

M: my-stream dispose* underlying>> dispose ;

Depois de isso estar pronto, todos os combinadores with-… de channel-chatter funcionam automaticamente no teu stream.

Instruções

És o telegrafista sem fios de um cargueiro. O sinal chega por uma linha ruidosa (a maquinaria do navio, o estático do tempo, uma conversa estrangeira ocasional), entremeado com o verdadeiro Morse que estás a tentar ouvir. Para apanhares a mensagem, fazes passar o fio por um dispositivo tape que elimina tudo exceto os símbolos de Morse válidos (., - e o espaço que separa as letras).

O teu trabalho é construir a tape como um fluxo de entrada personalizado do Factor.

1. Define a tape

Define um tuplo tape que estende disposable e tem uma única fenda, wire, para o fluxo de entrada subjacente.

TUPLE: tape < disposable wire ;

Depois escreve o construtor <tape> ( wire -- tape ). Usa new-disposable (e não new) para que o framework de destruição registe a tape, e guarda o fluxo subjacente na fenda wire.

2. Integra o mixin input-stream

Declara tape como um input-stream:

INSTANCE: tape input-stream

Isso faz com que os combinadores predefinidos do protocolo sejam encaminhados para a tua classe.

3. Lê um símbolo de Morse

Implementa M: tape stream-read1 ( tape -- elt/f ). Lê bytes do fio subjacente até encontrares um de CHAR: ., CHAR: - ou CHAR: \s (espaço). Devolve esse byte. Se o fio devolver f (fim do fluxo), devolve f também; a tape chegou ao fim.

"x.y -ab cz" <string-reader> <tape>
[ stream-read1 ] [ stream-read1 ] [ stream-read1 ] tri
! => CHAR: . CHAR: - CHAR: \s

4. Delega o tipo de elemento

Implementa M: tape stream-element-type ( tape -- type ) delegando no fio: a tape não altera o tipo de elementos que são lidos.

5. Liberta os recursos

Implementa M: tape dispose* ( tape -- ). O framework chama o teu método exatamente uma vez por cada dispose; basta libertares o fio subjacente.

Com estas cinco peças no lugar, a tape funciona como um fluxo de entrada normal: with-input-stream, stream-read e as restantes palavras do protocolo são encaminhadas automaticamente para os teus métodos.

Editar via GitHub A ligação abre numa nova janela ou separador
Factor Exercism

Estás pronto para começar Fita do Telegrafista?

Inscreve-te no Exercism para aprenderes e dominares Factor com 47 conceitos163 exercícios, e mentoria humana real, tudo grátis.