Introdução: Se você pesquisar na Internet por uma biblioteca que possa gerar sequências, dificilmente encontrará uma, embora as sequências sejam um conceito central da matemática discreta e da ciência da computação. Neste breve artigo, daremos uma olhada em uma biblioteca que escrevi para a geração de sequência chamada . SeqGen O que é uma sequência? Uma sequência (falando informalmente) é um conjunto de elementos (principalmente números) onde a produção de cada elemento é baseada no(s) elemento(s) anterior(es). O exemplo mais básico é uma sequência linear simples de inteiros positivos onde o primeiro elemento é 0 e o próximo elemento é o elemento anterior mais um, então podemos obter o segundo elemento adicionando um ao primeiro, e podemos obter o terceiro elemento adicionando um ao segundo e assim por diante. A sequência linear ficaria assim: . {0, 1, 2, 3, …, n} Um exemplo mais complexo poderia ser a sequência de Fibonacci, onde os dois primeiros elementos são 0 e 1, e o próximo elemento é a soma dos dois elementos anteriores. A sequência de Fibonacci ficaria assim: {0, 1, 1, 2, 3, 5, 8, 13, 21, …, n} Podemos notar acima que uma sequência é definida com duas propriedades: Os elementos iniciais Uma função que produz o próximo elemento Usando a Biblioteca: 2.0_ Dependências: A biblioteca SeqGen é escrita na linguagem de programação Rust; para acompanhar, você precisa ter . o Rust instalado 2.1_ Criando um Projeto: Vamos criar um novo projeto para utilizar a biblioteca SeqGen; podemos fazer isso com carga: $ cargo new --bin sequence && cd sequence Agora, vamos adicionar a biblioteca como dependência ao nosso projeto: $ cargo add seqgen Agora estamos prontos para usar a biblioteca. Criando uma sequência: No SeqGen, o processo de criação de sequência é mapeado diretamente para as duas propriedades da sequência que concluímos na seção O que é uma sequência; temos que definir os elementos iniciais e a função que produz o próximo elemento (chamada de função de transição no SeqGen). Vamos criar a sequência linear: use seqgen::prelude::*; fn main() { let linear_seq = Sequence::new() .initial_elements(vec![0]) .transition_function(|alive_elements, current_element_index| { alive_elements.last_element().unwrap() + 1 }); } O tipo é uma estrutura que representa uma sequência; chamando a função associada neste tipo, obtemos uma nova instância que é indefinida. Nesta instância indefinida, podemos chamar métodos para defini-la. Sequence new() O primeiro método é que aceita um vetor de elementos como argumento e o define como os elementos iniciais da instância. initial_elements() O segundo método é que toma como argumento um encerramento que representa a transição dos elementos atualmente disponíveis para o próximo elemento. transition_function() Este encerramento tem acesso a dois argumentos: o primeiro é que representa os elementos atualmente disponíveis, e o segundo é (do tipo ) que é o índice do elemento atual em geração. Veja a tabela abaixo para uma ilustração da função de transição. alive_elements current_element_index usize Elemento Atual na Geração elementos_vivos índice_elemento_atual 1 [0] 1 2 [0, 1] 2 3 [0, 1, 2] 3 n [0, 1, 2, 3, …, n] n é do tipo , daremos uma olhada no tipo posteriormente neste artigo alive_elements SequencePart SequencePart Como o índice do elemento também é o seu valor na sequência linear, podemos simplificar o exemplo acima para: use seqgen::prelude::*; fn main() { let linear_seq = Sequence::new().transition_function(|_, i| i); } Aqui, não precisamos definir os elementos iniciais e não precisamos de acesso aos elementos ativos; precisamos apenas do índice (que é denominado neste caso) e simplesmente o retornamos. i Da mesma forma, podemos definir a sequência de Fibonacci: use seqgen::prelude::*; fn main() { let fib_seq = Sequence::new() .initial_elements(vec![0, 1_u128]) .transition_function(|alive_elements, i| { let x = alive_elements.nth_element(i - 1).unwrap(); let y = alive_elements.nth_element(i - 2).unwrap(); x + y }); } Como a sequência de Fibonacci cresce exponencialmente, gerar mais de 187 elementos com esta definição fará com que estoure. Uma definição melhor usaria big int em vez de . u128 u128 : Usando a sequência Após definirmos nossa sequência, podemos acessar seus elementos: use seqgen::prelude::*; fn main() { let mut linear_seq = Sequence::new().transition_function(|_, i| i); let some_element = linear_seq.nth_element(111); println!("{some_element}"); } Aqui, estamos acessando o 111º elemento usando o método que retorna uma referência imutável ao elemento ( neste caso). nth_element() &usize Observe que tornamos mutável. Isso ocorre porque o método irá transformar os elementos vivos da sequência. linear_seq nth_element() Desta forma, podemos acessar qualquer elemento da sequência (desde o elemento com índice até o elemento com índice .) 0 usize::MAX Também podemos iterar sobre a sequência como qualquer iterador Rust: use seqgen::prelude::*; fn main() { let linear_seq = Sequence::new().transition_function(|_, i| i); linear_seq.for_each(|e| println!("{e}")); } Este código irá imprimir todos os elementos da sequência (do elemento ao elemento ): 0 usize::MAX $ cargo run -q 0 1 2 3 4 5 6 7 8 9 10 11 12 13 ... Podemos obter os elementos ímpares da sequência usando o seguinte código: use seqgen::prelude::*; fn main() { let linear_seq = Sequence::new().transition_function(|_, i| i); let odd_elements = linear_seq.filter(|e| e % 2 != 0); odd_elements.for_each(|e| println!("{e}")); } Saída: $ cargo run -q 1 3 5 7 9 11 13 ... A sequência que definimos é lenta, o que significa que os elementos não serão gerados a menos que sejam necessários (em caso de iteração) ou solicitados explicitamente (usando o método ). nth_element() : Trabalhando com partes da sequência Às vezes precisamos trabalhar apenas com partes de uma sequência, neste caso temos partes de sequência. Existem três tipos de parte de sequência: AliveElementsPart ImmutableRangePart MutableRangePart AliveElementsParte: Podemos obter os elementos vivos usando o método na sequência: alive_elements() use seqgen::prelude::*; fn main() { let linear_seq = Sequence::new() .transition_function(|_, i| i) .pre_generate(111); let alive_elements = linear_seq.alive_elements(); for alive_element in alive_elements { print!("{alive_element} "); } } Este código imprimirá todos os elementos vivos (0 a 110 neste caso porque pré-geramos 111 elementos). FaixaImutávelParte: As faixas imutáveis são as faixas dos elementos vivos; eles não podem alterar a sequência. Se você criar um intervalo imutável e nem todos os seus elementos estiverem ativos, você receberá um erro (erro ). DeadRange Podemos criar um intervalo imutável usando o método que retorna um . A variante é e a variante é . O pode ser a variante (caso o início do intervalo seja maior que o final) ou pode ser a variante (caso nem todos os elementos do intervalo estejam ativos): range() Result Ok ImmutableRangePart Err RangeError RangeError InvalidRange DeadRange use seqgen::prelude::*; fn main() { let linear_seq = Sequence::new().transition_function(|_, i| i); let range = linear_seq.range(0, 3).unwrap(); for e in range { println!("{e}") } } Este código entrará em pânico com o erro porque não há nenhum elemento ativo. Podemos corrigir isso com o seguinte: DeadRange use seqgen::prelude::*; fn main() { let mut linear_seq = Sequence::new().transition_function(|_, i| i); linear_seq.generate(3); let range = linear_seq.range(0, 3).unwrap(); for e in range { println!("{e}") } } Aqui, geramos 3 elementos para tornar o intervalo válido. MutableRangePart: Um intervalo mutável pode alterar a sequência (gerar elementos). Podemos usar um intervalo mutável assim: use seqgen::prelude::*; fn main() { let mut linear_seq = Sequence::new().transition_function(|_, i| i); let mut_range = linear_seq.range_mut(0, 111).unwrap(); for e in mut_range { println!("{e}"); } } Este código imprimirá os elementos de 0 a 110. Outradução: Obrigado por ler este artigo até o fim e espero que você tenha encontrado algo útil nele. Se você tiver alguma sugestão que possa melhorar esta biblioteca, , e se quiser , isso seria maravilhoso. abra um issue no GitHub contribuir com a biblioteca Também publicado aqui