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

Fita do Telegrafista

Exercício de aprendizagem

Introdução

Você já usou streams em channel-chatter e já os descartou em boatswains-bilge. Este exercício é o seu primeiro stream personalizado: uma classe que implementa o protocolo, de modo que o mesmo código with-input-stream / read1 / stream-read1 que funcionava em um <string-reader> funcione no seu.

Mixins: a outra metade da hierarquia de classes

Você já conhece TUPLE: child < parent … de dragons-descendants, uma hierarquia de pai único em que os slots descem. O Factor tem uma segunda forma de estender o grafo de classes: os mixins abertos. Um MIXIN: m declara uma classe sem slots na qual outras classes podem entrar depois, com INSTANCE: c m. A associação é muitos-para-muitos: uma classe pode ser instância de quantos mixins quiser.

O protocolo de streams usa dois mixins para marcar qual 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 os dois. Os métodos genéricos de input-stream (ou output-stream) então despacham para qualquer classe que tenha aderido ao mixin. É assim que read1, stream-contents, with-input-stream e outros do ambiente chegam até a sua classe.

Os mixins são abertos: você pode adicionar um novo membro depois que o mixin foi declarado, até mesmo em um vocabulário diferente. É esse o contraste com TUPLE: < parent, em que a relação é fixada quando a classe filha é declarada.

Os genéricos do protocolo

Os genéricos do protocolo ficam 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 )

stream-read1 retorna o próximo byte (ou f no fim do stream); stream-write1 escreve um. stream-read-unsafe é a leitura em lote de mais baixo nível que a maioria dos streams de entrada fornece; stream-read é construído em cima dela e cuida da alocação. stream-element-type diz se o stream lida com bytes (+byte+) ou caracteres (+character+); quando você envolve outro stream, a implementação mais simples apenas delega para o stream subjacente.

A limpeza vem de destructors

Streams são descartáveis: um stream personalizado estende disposable e implementa dispose*. É 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 que isso estiver pronto, todos os combinadores with-… de channel-chatter funcionam no seu stream automaticamente.

Instruções

Você é o radiotelegrafista de um cargueiro. O sinal chega por uma linha ruidosa, com o barulho das máquinas do navio, estática do tempo e conversas estrangeiras ocasionais, tudo intercalado com o Morse que você está tentando ouvir. Para captar a mensagem, você passa o fio por um dispositivo de fita que remove tudo, exceto os símbolos Morse válidos (., - e o espaço que separa as letras).

Seu trabalho é construir a fita como um fluxo de entrada personalizado do Factor.

1. Defina a fita

Defina uma tupla tape que estende disposable e contém um slot, wire, para o fluxo de entrada subjacente.

TUPLE: tape < disposable wire ;

Depois escreva o construtor <tape> ( wire -- tape ). Use new-disposable (e não new) para que o framework do destrutor registre a fita, e guarde o fluxo subjacente no slot wire.

2. Adira ao mixin input-stream

Declare que tape é um input-stream:

INSTANCE: tape input-stream

Assim, os combinadores padrão do protocolo despacham para a sua classe.

3. Leia um símbolo Morse

Implemente M: tape stream-read1 ( tape -- elt/f ). Leia bytes do fio subjacente até encontrar um de CHAR: ., CHAR: - ou CHAR: \s (espaço). Retorne esse byte. Se o fio retornar f (fim de fluxo), retorne f também: a fita acabou.

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

4. Delegue o tipo de elemento

Implemente M: tape stream-element-type ( tape -- type ) delegando ao fio: a fita não muda o tipo de elementos que estão sendo lidos.

5. Faça a limpeza

Implemente M: tape dispose* ( tape -- ). O framework chama o seu método exatamente uma vez por dispose; basta descartar o fio subjacente.

Com essas cinco peças no lugar, a fita funciona como um fluxo de entrada comum: with-input-stream, stream-read e as demais palavras do protocolo despacham automaticamente para os seus métodos.

Editar via GitHub O link abre em uma nova janela ou aba
Factor Exercism

Tudo pronto para começar Fita do Telegrafista?

Crie sua conta no Exercism para aprender e dominar Factor com 47 conceitos163 exercícios e mentoria humana de verdade, tudo de graça.