Elixir: Conjuntos em 3 Atos

Elixir: Conjuntos em 3 Atos

Ato I: porque vale a pena saber usar MapSet em Elixir, com exemplos
práticos de código mais legível e eficiente pelo uso de união,
interseção, diferença etc.;

Ato II: análise da interface de MapSet, e como se compara a conjuntos em outras linguagens modernas importantes;

Ato III: interface versus implementação—como implementei UintSet, um tipo de conjunto para inteiros baseado em um vetor de bits.

27c093d0834208f4712faaaec38c2c5c?s=128

Luciano Ramalho

May 25, 2019
Tweet

Transcript

  1. p o r q u e e c o m

    o CONJUNTOS EM 3 ATOS Porque conjuntos simplificam a lógica,
 e como eles são construídos em Elixir Luciano Ramalho @ramalhoorg Com emojis de gatinhos!
  2. PALESTRA EM 3 ATOS 1
 Porque conjuntos podem simplificar seu

    código 2 2
 Como é a API de MapSet 3
 Como implementar
 uma coleção como MapSet
  3. PORQUE USAR CONJUNTOS Alguns casos de usos comuns para conjuntos

    3
  4. CASO DE USO #1: RUNE FINDER 4 query = ["FACE"]

    Exibir item se todas as palavras da consulta aparecem na descrição.
  5. CASO DE USO #1: RUNE FINDER 5 query = ["FACE"]

    Exibir item se todas as palavras da consulta aparecem na descrição.
  6. CASO DE USO #1: RUNE FINDER 6 query = ["FACE"]

    Exibir item se todas as palavras da consulta aparecem na descrição.
  7. CASO DE USO #1: RUNE FINDER 7

  8. CASO DE USO #1: RUNE FINDER 8 UnicodeData.txt ... 1F637;FACE

    WITH MEDICAL MASK 1F638;GRINNING CAT FACE WITH SMILING EYES 1F639;CAT FACE WITH TEARS OF JOY 1F63A;SMILING CAT FACE WITH OPEN MOUTH 1F63B;SMILING CAT FACE WITH HEART-SHAPED EYES 1F63C;CAT FACE WITH WRY SMILE 1F63D;KISSING CAT FACE WITH CLOSED EYES 1F63E;POUTING CAT FACE 1F63F;CRYING CAT FACE 1F640;WEARY CAT FACE 1F641;SLIGHTLY FROWNING FACE 1F642;SLIGHTLY SMILING FACE 1F643;UPSIDE-DOWN FACE 1F644;FACE WITH ROLLING EYES ...
  9. CASO DE USO #1: RUNE FINDER 9 query = ["FACE"]

    ... 1F637;FACE WITH MEDICAL MASK 1F638;GRINNING CAT FACE WITH SMILING EYES 1F639;CAT FACE WITH TEARS OF JOY 1F63A;SMILING CAT FACE WITH OPEN MOUTH 1F63B;SMILING CAT FACE WITH HEART-SHAPED EYES 1F63C;CAT FACE WITH WRY SMILE 1F63D;KISSING CAT FACE WITH CLOSED EYES 1F63E;POUTING CAT FACE 1F63F;CRYING CAT FACE 1F640;WEARY CAT FACE 1F641;SLIGHTLY FROWNING FACE 1F642;SLIGHTLY SMILING FACE 1F643;UPSIDE-DOWN FACE 1F644;FACE WITH ROLLING EYES ...
  10. CASO DE USO #1: RUNE FINDER 10 query = ["FACE",

    "CAT"] ... 1F637;FACE WITH MEDICAL MASK 1F638;GRINNING CAT FACE WITH SMILING EYES 1F639;CAT FACE WITH TEARS OF JOY 1F63A;SMILING CAT FACE WITH OPEN MOUTH 1F63B;SMILING CAT FACE WITH HEART-SHAPED EYES 1F63C;CAT FACE WITH WRY SMILE 1F63D;KISSING CAT FACE WITH CLOSED EYES 1F63E;POUTING CAT FACE 1F63F;CRYING CAT FACE 1F640;WEARY CAT FACE 1F641;SLIGHTLY FROWNING FACE 1F642;SLIGHTLY SMILING FACE 1F643;UPSIDE-DOWN FACE 1F644;FACE WITH ROLLING EYES ...
  11. CASO DE USO #1: RUNE FINDER 11 query = ["FACE",

    "CAT", "EYES"] ... 1F637;FACE WITH MEDICAL MASK 1F638;GRINNING CAT FACE WITH SMILING EYES 1F639;CAT FACE WITH TEARS OF JOY 1F63A;SMILING CAT FACE WITH OPEN MOUTH 1F63B;SMILING CAT FACE WITH HEART-SHAPED EYES 1F63C;CAT FACE WITH WRY SMILE 1F63D;KISSING CAT FACE WITH CLOSED EYES 1F63E;POUTING CAT FACE 1F63F;CRYING CAT FACE 1F640;WEARY CAT FACE 1F641;SLIGHTLY FROWNING FACE 1F642;SLIGHTLY SMILING FACE 1F643;UPSIDE-DOWN FACE 1F644;FACE WITH ROLLING EYES ...
  12. CASO DE USO #1: SOLUÇÃO DESCONJUNTADA Já escrevi código assim

    em Go* 12 *Go 1.12 ainda não tem conjuntos na sua biblioteca padrão
  13. CASO DE USO #1: SOLUÇÃO DESCONJUNTADA Já escrevi código assim

    em Go* 13 *Go 1.12 ainda não tem conjuntos na sua biblioteca padrão
  14. CASO DE USO #1: SOLUÇÃO DESCONJUNTADA 2 Mais legível, mas

    ainda deixa a desejar... 14
  15. CASO DE USO #1: SOLUÇÃO DESCONJUNTADA 2 Mais legível, mas

    ainda deixa a desejar... 15
  16. 16 E se… Agora não! Estou muito ocupado codando laços

    aninhados! www.workcompass.com/
  17. JOHN BACKUS — TURING AWARD LECTURE, 1977 17

  18. CASO DE USO #1: RUNE FINDER 18 www.workcompass.com/ Exibir item

    se todas as palavras da consulta aparecem na descrição.
  19. CASO DE USO #1: RUNE FINDER 19 Q ⊂ D

    www.workcompass.com/ Exibir item se todas as palavras da consulta aparecem na descrição.
  20. CASO DE USO #1: RUNE FINDER 20 https://github.com/standupdev/rf

  21. CASO DE USO #1: RUNE FINDER 21 Tokenize: transforma query

    e descrição em conjuntos www.workcompass.com/ https://github.com/standupdev/rf
  22. CASO DE USO #1: RUNE FINDER 22 Q ⊂ D

    www.workcompass.com/ https://github.com/standupdev/rf
  23. CASO DE USO #2: GIMEL Outro buscador de emojis, com

    uma estratégia diferente. rf.exs: percorre UnicodeData.txt inteiro a cada consulta; estratégia grep. Gimel: percorre UnicodeData.txt só uma vez ao iniciar, criando dois índices que são usados nas consultas; estratégia índice invertido. 23
  24. GIMEL: UM CONSOLE PARA ACHAR CARACTERES UNICODE 24

  25. GIMEL: UM CONSOLE PARA ACHAR CARACTERES UNICODE 25

  26. GIMEL: UM CONSOLE PARA ACHAR CARACTERES UNICODE 26

  27. COMO FUNCIONA UM ÍNDICE INVERTIDO %{ palavra_chave => conjunto_de_ocorrências, …

    } 27
  28. COMO FUNCIONA UM ÍNDICE INVERTIDO Para encontrar os três gatinhos,

    pegue a intersecção das ocorrências de "FACE", "CAT", e "EYES": 28
  29. INTERSECÇÃO DAS OCORRÊNCIAS: 3 GATINHOS 29 ⚄ ⾯面 ☹ ὺ

    ⚃ ☺ ⚀ ⚂ ⚁ ☻ ⚅ ꊶ (F ∩ C) ∩ E Face Cat Eyes query = ["FACE", "CAT", "EYES"] Nota: este diagrama não está correto. Deveria haver emojis nas intersecções entre dois conjuntos: F ∩ C, F ∩ E, C ∩ E
  30. CASO DE USO #2: GIMEL, FUNÇÃO SEARCH/2 30 https://github.com/standupdev/gimel

  31. CASO DE USO #2: GIMEL, FUNÇÃO SEARCH/2 31 https://github.com/standupdev/gimel Inicia

    redução com ocorrências da primeira palavra
  32. CASO DE USO #2: GIMEL, FUNÇÃO SEARCH/2 32 https://github.com/standupdev/gimel A

    ∩ B ∩ C ∩ D...
  33. CASO DE USO #3: LOJA ONLINE 33 Destacar todos os

    produtos favoritados, exceto aqueles que já estão no carrinho de compras.
  34. CASO DE USO #3: LOJA ONLINE 34 Destacar todos os

    produtos favoritados, exceto aqueles que já estão no carrinho de compras. F ∖ C Diferença entre
 conjuntos:
  35. LÓGICA E CONJUNTOS Uma relação íntima 35

  36. Nobody has yet discovered a branch of mathematics that has

    successfully resisted formalization into set theory. Thomas Forster
 Logic Induction and Sets, p. 167 36
  37. Ninguém descobriu ainda um ramo da matemática que tenha resistido

    à formalização através da teoria dos conjuntos. Thomas Forster
 Indução Lógica e Conjuntos, p. 167 37
  38. CONJUNÇÃO LÓGICA É INTERSECÇÃO "x pertence à intersecção de A

    com B" é o mesmo que: "x pertence a A e x pertence a B." Em matemática: x ∈ (A ∩ B) ⟺ (x ∈ A) ∧ (x ∈ B) Em Elixir: MapSet.intersection Bitwise.band/2, &&& 38
  39. DISJUNÇÃO LÓGICA É UNIÃO "x pertence à união de A

    com B" é o mesmo que: "x pertence a A ou x pertence a B" Em matemática: x ∈ (A ∪ B) ⟺ (x ∈ A) ∨ (x ∈ B) Em Elixir: MapSet.union/2,
 Bitwise.bor/2, ||| 39
  40. DIFERENÇA "x pertence a A mas não pertence a B"

    é o mesmo que: "elementos de A menos elementos de B" Notação matemática: x ∈ (A ∖ B) ⟺ (x ∈ A) ∧ (x ∉ B) Em Elixir: MapSet.difference/2 40
  41. DIFERENÇA SIMÉTRICA "x pertence a A ou x pertence a

    B mas não pertence a ambos" é o mesmo que: "x pertence à união de A com B menos a intersecção de A com B" Em matemática: 
 Em Elixir: Bitwise.bxor/2, ^^^ 41 x ∈ (A ∆ B) ⟺ (x ∈ A) ⊻ (x ∈ B)
  42. CONJUNTOS EM VÁRIAS LINGUAGENS Como Elixir se compara 42

  43. CONJUNTOS EM VÁRIAS LINGUAGENS/PLATAFORMAS Amostra de linguagens ou APIs de

    plataformas que oferecem conjuntos em sua biblioteca-padrão. 43 Elixir MapSet: 14 métodos Ruby Set: > 10 métodos e operadores Python set, frozenset: > 10 métodos e operadores .Net (C# etc.) ISet interface: > 10 métodos; 2 implementações JavaScript (ES6) Set: < 10 métodos Java Set interface: < 10 métodos; 8 implementações Go Faça você mesmo, ou escolha um dos N pacotes...
  44. CONJUNTOS EM VÁRIAS LINGUAGENS/PLATAFORMAS Amostra de linguagens ou APIs de

    plataformas que oferecem conjuntos em sua biblioteca-padrão. 44 Elixir MapSet: 14 métodos Ruby Set: > 10 métodos e operadores Python set, frozenset: > 10 métodos e operadores .Net (C# etc.) ISet interface: > 10 métodos; 2 implementações JavaScript (ES6) Set: < 10 métodos Java Set interface: < 10 métodos; 8 implementações Go Faça você mesmo, ou escolha um dos N pacotes...
  45. MAPSET Recomendado desde Elixir v1.2 (2016) 45

  46. INTERFACE DE MAPSET Construção 46 new() Cria um novo MapSet

    vazio. new(enum) Cria um MapSet a partir de um enumerável. new(enum, transform) Idem, aplicando função transform a cada elemento. member?(set, elemento) Testa se o elemento pertence ao MapSet. put(set, elemento) Insere o elemento. Se há membro igual, nada acontece. delete(set, elemento) Retira o elemento do MapSet. size(set) Devolve o número de elementos do MapSet. to_list(set) Cria uma lista a partir do MapSet. Operações básicas
  47. INTERFACE DE MAPSET Operações entre conjuntos — devolvem novo MapSet

    47 intersection(set1, set2) Intersecção entre dois MapSet. A ∩ B union(set1, set2) União de dois MapSet. A ∪ B difference(set1, set2) Diferença set1 ➖ set2. A ∖ B Testes — devolvem booleano member?(set, elemento) Elemento pertence ao MapSet? x ∈ A subset?(set1, set2) Todos os elementos de set1 estão em set2? A ⊆ B equal?(set1, set2) set1 e set2 tem os mesmos elementos? A = B disjoint?(set1, set2) set1 e set2 não tem elementos em comum? A ∩ B = ∅
  48. UINTSET Conjunto para inteiros pequenos. 48

  49. ORIGEM DA IDEIA: THE GO PROGRAMMING LANGUAGE The Go Programming

    Language Alan A. A. Donovan & Brian W. Kernighan 49
  50. INTERFACE DE UINTSET Construção — como MapSet, só para elementos

    inteiros 50 new() Cria um novo UintSet vazio. new(enum) Cria um UintSet a partir de um enumerável. new(enum, transform) Idem, aplicando função transform a cada elemento. member?(set, elemento) Testa se o elemento pertence ao UintSet. put(set, elemento) Insere o elemento. Se há membro igual, nada acontece. delete(set, elemento) Retira o elemento do UintSet. length(set) Devolve o número de elementos do UintSet — O(n). to_list(set) Cria uma lista a partir do UintSet. Operações básicas — a função diferente: size/1 ≠ length/1
  51. INTERFACE DE UINTSET Operações entre conjuntos — devolvem novo UintSet

    51 intersection(set1, set2) Intersecção entre dois UintSet. A ∩ B union(set1, set2) União de dois UintSet. A ∪ B difference(set1, set2) Diferença set1 ➖ set2. A ∖ B Testes — devolvem booleano member?(set, elemento) Elemento pertence ao UintSet? x ∈ A subset?(set1, set2) Todos os elementos de set1 estão em set2? A ⊆ B equal?(set1, set2) set1 e set2 tem os mesmos elementos? A = B disjoint?(set1, set2) set1 e set2 não tem elementos em comum? A ∩ B = ∅
  52. ESTRUTURA INTERNA DE UINTSET: UM (BIG) INTEGER 52

  53. ESTRUTURA INTERNA DE UINTSET: UM (BIG) INTEGER 53

  54. ESTRUTURA INTERNA DE UINTSET: UM (BIG) INTEGER 54

  55. ESTRUTURA INTERNA DE UINTSET: UM (BIG) INTEGER 55

  56. ESTRUTURA INTERNA DE UINTSET: UM (BIG) INTEGER 56

  57. ESTRUTURA INTERNA DE UINTSET: UM (BIG) INTEGER 57

  58. ESTRUTURA INTERNA DE UINTSET: UM (BIG) INTEGER 58

  59. IMPLEMENTAÇÃO Código-fonte de UintSet 59

  60. SHOW ME THE CODE 60 https://github.com/ramalho/uint_set

  61. UINTSET: EMULANDO MAPSET SOBRE VETOR DE BITS 61

  62. UINTSET: EMULANDO MAPSET SOBRE VETOR DE BITS Note o struct

    com 1 campo: bits 62
  63. UINTSET: NEW/0 — NEW/1 — NEW/2 63

  64. BITOPS: TRATANDO UM INTEIRO COMO VETOR DE BITS 64

  65. BITOPS: SET_BIT/2 — UNSET_BIT/2 65

  66. BITOPS: LIST_ONES/1 66

  67. BITOPS: STREAM_ONES/1 67

  68. UINTSET: NEW/0 — NEW/1 — NEW/2 68

  69. UINTSET: DELETE/2 — DIFFERENCE/2 — DISJOINT/2 69

  70. EQUAL?/2 INTERSECTION/2 LENGTH/1 MEMBER?/1 PUT/2 70

  71. STREAM/1 — SUBSET/2 — TO_LIST/1 — UNION/2 71

  72. PROTOCOLO ENUMERABLE 72

  73. PROTOCOLOS: COLLECTABLE — INSPECT 73

  74. CONCLUSÃO Resumindo 74

  75. APRENDENDO COM CONJUNTOS Operações com conjuntos podem simplificar algoritmos. Elixir

    oferece uma implementação rica: MapSet. O código de MapSet é um excelente exemplo de abstração de dados usando struct e protocolos. A interface de UintSet é quase a mesma de MapSet,
 mas a implementação é mais simples, com operadores Bitwise para manipular inteiros como vetores de bits. 75 https://github.com/ramalho/uint_set
  76. Luciano Ramalho
 @ramalhoorg | @standupdev
 luciano.ramalho@thoughtworks.com MUITO GRATO!

  77. Luciano Ramalho
 @ramalhoorg | @standupdev
 luciano.ramalho@thoughtworks.com MUITO GRATO!