$30 off During Our Annual Pro Sale. View Details »

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.

Luciano Ramalho

May 25, 2019
Tweet

More Decks by Luciano Ramalho

Other Decks in Programming

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!

    View Slide

  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

    View Slide

  3. PORQUE USAR
    CONJUNTOS
    Alguns casos de usos comuns para conjuntos
    3

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  7. CASO DE USO #1: RUNE FINDER
    7

    View Slide

  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
    ...

    View Slide

  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
    ...

    View Slide

  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
    ...

    View Slide

  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
    ...

    View Slide

  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

    View Slide

  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

    View Slide

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

    View Slide

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

    View Slide

  16. 16
    E se…
    Agora não! Estou
    muito ocupado
    codando laços
    aninhados!
    www.workcompass.com/

    View Slide

  17. JOHN BACKUS — TURING AWARD LECTURE, 1977
    17

    View Slide

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

    View Slide

  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.

    View Slide

  20. CASO DE USO #1: RUNE FINDER
    20
    https://github.com/standupdev/rf

    View Slide

  21. CASO DE USO #1: RUNE FINDER
    21
    Tokenize: transforma
    query e descrição em
    conjuntos
    www.workcompass.com/
    https://github.com/standupdev/rf

    View Slide

  22. CASO DE USO #1: RUNE FINDER
    22
    Q ⊂ D
    www.workcompass.com/
    https://github.com/standupdev/rf

    View Slide

  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

    View Slide

  24. GIMEL: UM CONSOLE PARA ACHAR CARACTERES UNICODE
    24

    View Slide

  25. GIMEL: UM CONSOLE PARA ACHAR CARACTERES UNICODE
    25

    View Slide

  26. GIMEL: UM CONSOLE PARA ACHAR CARACTERES UNICODE
    26

    View Slide

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

    View Slide

  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

    View Slide

  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

    View Slide

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

    View Slide

  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

    View Slide

  32. CASO DE USO #2: GIMEL, FUNÇÃO SEARCH/2
    32
    https://github.com/standupdev/gimel
    A ∩ B ∩ C ∩ D...

    View Slide

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

    View Slide

  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:

    View Slide

  35. LÓGICA E CONJUNTOS
    Uma relação íntima
    35

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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

    View Slide

  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)

    View Slide

  42. CONJUNTOS EM
    VÁRIAS LINGUAGENS
    Como Elixir se compara
    42

    View Slide

  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...

    View Slide

  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...

    View Slide

  45. MAPSET
    Recomendado desde Elixir v1.2 (2016)
    45

    View Slide

  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

    View Slide

  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 = ∅

    View Slide

  48. UINTSET
    Conjunto para inteiros pequenos.
    48

    View Slide

  49. ORIGEM DA IDEIA: THE GO PROGRAMMING LANGUAGE
    The Go Programming Language
    Alan A. A. Donovan & Brian W. Kernighan
    49

    View Slide

  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

    View Slide

  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 = ∅

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  61. UINTSET: EMULANDO MAPSET SOBRE VETOR DE BITS
    61

    View Slide

  62. UINTSET: EMULANDO MAPSET SOBRE VETOR DE BITS
    Note o struct com 1 campo: bits
    62

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  66. BITOPS: LIST_ONES/1
    66

    View Slide

  67. BITOPS: STREAM_ONES/1
    67

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  72. PROTOCOLO ENUMERABLE
    72

    View Slide

  73. PROTOCOLOS: COLLECTABLE — INSPECT
    73

    View Slide

  74. CONCLUSÃO
    Resumindo
    74

    View Slide

  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

    View Slide

  76. Luciano Ramalho

    @ramalhoorg | @standupdev

    [email protected]
    MUITO GRATO!

    View Slide

  77. Luciano Ramalho

    @ramalhoorg | @standupdev

    [email protected]
    MUITO GRATO!

    View Slide