A Lever for the Mind

Cd9b247e4507fed75312e9a42070125d?s=47 Tom Stuart
November 19, 2014

A Lever for the Mind

Humans are the cleverest animals in the known universe. But our brains, forged over millions of years in the unforgiving furnace of natural selection, are still primitive. They evolved to be good at hunting animals, making tools, recognising facial expressions and maintaining social bonds, but they’re just not very good at working with several difficult ideas simultaneously, and they’re particularly bad at reasoning about the counterintuitive emergent behaviour of complex non-human systems.

That’s a problem, because complex non-human systems now dominate our world.

Abstraction is our solution to this problem. Abstraction works as an adapter between the fearsome complexity of the universe and our simple primate minds; when the real world is too detailed, too confusing or too counterintuitive for us to work with directly, abstraction gives us big friendly levers to pull on instead. This one powerful idea underlies computers, design, culture, language, and everything else we rely on in our daily work.

This is a talk about abstraction: where it comes from, what it’s for, and how we can use it to make our programs better.

Given at RubyConf 2014 (http://lanyrd.com/2014/rubyconf/) and Bath Ruby Conference 2015 (http://2015.bathruby.org/). A video and transcript is available at http://codon.com/a-lever-for-the-mind.

Cd9b247e4507fed75312e9a42070125d?s=128

Tom Stuart

November 19, 2014
Tweet

Transcript

  1. 2.

    Give me a lever long enough and a fulcrum on

    which to place it, and I shall move the world.” — Archimedes “
  2. 3.
  3. 5.
  4. 6.
  5. 7.
  6. 8.
  7. 9.
  8. 10.
  9. 11.
  10. 12.
  11. 13.
  12. 14.
  13. 15.

    3

  14. 16.
  15. 17.
  16. 18.
  17. 19.
  18. 20.
  19. 21.

    <

  20. 22.
  21. 23.
  22. 24.
  23. 25.
  24. 26.
  25. 27.
  26. 28.

    3

  27. 31.
  28. 32.

    1 + 2 + 3 + 4 + 5 +

    6 + 7 + 8 + 9 + 10 = ?
  29. 33.

    1 + 2 = 3 3 + 3 = 6

    6 + 4 = 10 10 + 5 = 15
  30. 34.

    15 + 6 = 21 21 + 7 = 28

    28 + 8 = 36 36 + 9 = 45 45 + 10 = 55
  31. 35.

    1 + 2 + 3 + 4 + 5 +

    6 + 7 + 8 + 9 + 10 = 55
  32. 36.

    1 + 2 + 3 + 4 + 5 +

    … … + 98 + 99 + 100 = ?
  33. 37.

    ? 1 + 2 + 3 + 4 + 5

    + 6 + 7 + 8 + 9 + 10 =
  34. 38.

    ? 1 + 10 + 2 + 9 + 3

    + 8 + 4 + 7 + 5 + 6 =
  35. 41.

    1 + 10 + 2 + 9 + 3 +

    8 + 4 + 7 + 5 + 6 = 55
  36. 42.

    1 + 2 + … + 9 + 10 =

    (10 ÷ 2) × (10 + 1)
  37. 43.

    1 + 2 + 3 + 4 + 5 +

    … … + 98 + 99 + 100 = ?
  38. 44.

    1 + 100 + 2 + 99 + 49 +

    52 + 50 + 51 = ? ⋮
  39. 47.

    1 + 2 + … + 99 + 100 =

    (100 ÷ 2) × (100 + 1)
  40. 48.

    1 + 2 + … + n = (n ÷

    2) × (n + 1)
  41. 49.
  42. 50.
  43. 51.
  44. 52.
  45. 53.

    1 + 2 + … + n = (n +

    1) × n ÷ 2 ( )
  46. 55.

    1 + 2 + … + 999 + 1000 =

    (1000 ÷ 2) × (1000 + 1)
  47. 56.
  48. 58.
  49. 59.
  50. 60.
  51. 61.
  52. 62.
  53. 63.
  54. 64.
  55. 65.
  56. 66.
  57. 67.
  58. 68.
  59. 69.
  60. 70.
  61. 71.
  62. 72.
  63. 73.
  64. 74.
  65. 75.
  66. 76.
  67. 77.
  68. 78.
  69. 79.
  70. 80.
  71. 81.
  72. 82.
  73. 83.
  74. 84.
  75. 87.
  76. 88.
  77. 89.
  78. 90.
  79. 91.
  80. 92.
  81. 94.
  82. 95.
  83. 96.

  84. 97.
  85. 98.
  86. 108.
  87. 109.
  88. 110.
  89. 113.

    Card = Struct.new(:rank, :suit) three_of_diamonds = Card.new(3, :diamonds) queen_of_hearts =

    Card.new(12, :hearts) ace_of_spades = Card.new(14, :spades)
  90. 116.

    Hand = Struct.new(:cards) do include Comparable def <=>(other) if highest_card_rank

    == other.highest_card_rank without { |c| c.rank == highest_card_rank } <=> other.without { |c| c.rank == highest_card_rank } else highest_card_rank <=> other.highest_card_rank end end # … end
  91. 117.

    Hand = Struct.new(:cards) do include Comparable def <=>(other) if empty?

    && other.empty? 0 elsif highest_card_rank == other.highest_card_rank without { |c| c.rank == highest_card_rank } <=> other.without { |c| c.rank == highest_card_rank } else highest_card_rank <=> other.highest_card_rank end end # … end
  92. 118.

    Hand = Struct.new(:cards) do include Comparable def <=>(other) if one_pair?

    if other.one_pair? if highest_pair_rank == other.highest_pair_rank without { |c| c.rank == highest_pair_rank } <=> other.without { |c| c.rank == highest_pair_rank } else highest_pair_rank <=> other.highest_pair_rank end else 1 end else if empty? && other.empty? 0 elsif other.one_pair? -1 elsif highest_card_rank == other.highest_card_rank without { |c| c.rank == highest_card_rank } <=> other.without { |c| c.rank == highest_card_rank } else highest_card_rank <=> other.highest_card_rank end end end # … end
  93. 119.

    Hand = Struct.new(:cards) do include Comparable def <=>(other) if two_pair?

    if other.two_pair? if highest_pair_rank == other.highest_pair_rank without { |c| c.rank == highest_pair_rank } <=> other.without { |c| c.rank == highest_pair_rank } else highest_pair_rank <=> other.highest_pair_rank end else 1 end elsif one_pair? if other.two_pair? -1 elsif other.one_pair? if highest_pair_rank == other.highest_pair_rank without { |c| c.rank == highest_pair_rank } <=> other.without { |c| c.rank == highest_pair_rank } else highest_pair_rank <=> other.highest_pair_rank end else 1 end else if empty? && other.empty? 0 elsif other.one_pair? || other.two_pair? -1 elsif highest_card_rank == other.highest_card_rank without { |c| c.rank == highest_card_rank } <=> other.without { |c| c.rank == highest_card_rank } else highest_card_rank <=> other.highest_card_rank end end end # … end
  94. 120.

    Hand = Struct.new(:cards) do include Comparable def <=>(other) if three_of_a_kind?

    if other.three_of_a_kind? if highest_triple_rank == other.highest_triple_rank without { |c| c.rank == highest_triple_rank } <=> other.without { |c| c.rank == highest_triple_rank } else highest_triple_rank <=> other.highest_triple_rank end else 1 end elsif two_pair? if other.three_of_a_kind? -1 elsif other.two_pair? if highest_pair_rank == other.highest_pair_rank without { |c| c.rank == highest_pair_rank } <=> other.without { |c| c.rank == highest_pair_rank } else highest_pair_rank <=> other.highest_pair_rank end else 1 end elsif one_pair? if other.two_pair? || other.three_of_a_kind? -1 elsif other.one_pair? if highest_pair_rank == other.highest_pair_rank without { |c| c.rank == highest_pair_rank } <=> other.without { |c| c.rank == highest_pair_rank } else highest_pair_rank <=> other.highest_pair_rank end else 1 end else if empty? && other.empty? 0 elsif other.one_pair? || other.two_pair? || other.three_of_a_kind? -1 elsif highest_card_rank == other.highest_card_rank without { |c| c.rank == highest_card_rank } <=> other.without { |c| c.rank == highest_card_rank } else highest_card_rank <=> other.highest_card_rank end end end # … end
  95. 121.

    Hand = Struct.new(:cards) do include Comparable def <=>(other) if straight?

    if other.straight? if highest_straight_rank == other.highest_straight_rank without { |c| c.rank == highest_straight_rank } <=> other.without { |c| c.rank == highest_straight_rank } else highest_straight_rank <=> other.highest_straight_rank end else 1 end elsif three_of_a_kind? if other.straight? -1 elsif other.three_of_a_kind? if highest_triple_rank == other.highest_triple_rank without { |c| c.rank == highest_triple_rank } <=> other.without { |c| c.rank == highest_triple_rank } else highest_triple_rank <=> other.highest_triple_rank end else 1 end elsif two_pair? if other.three_of_a_kind? || other.straight? -1 elsif other.two_pair? if highest_pair_rank == other.highest_pair_rank without { |c| c.rank == highest_pair_rank } <=> other.without { |c| c.rank == highest_pair_rank } else highest_pair_rank <=> other.highest_pair_rank end else 1 end elsif one_pair? if other.two_pair? || other.three_of_a_kind? || other.straight? -1 elsif other.one_pair? if highest_pair_rank == other.highest_pair_rank without { |c| c.rank == highest_pair_rank } <=> other.without { |c| c.rank == highest_pair_rank } else highest_pair_rank <=> other.highest_pair_rank end else 1 end else if empty? && other.empty? 0 elsif other.one_pair? || other.two_pair? || other.three_of_a_kind? || other.straight? -1 elsif highest_card_rank == other.highest_card_rank without { |c| c.rank == highest_card_rank } <=> other.without { |c| c.rank == highest_card_rank } else highest_card_rank <=> other.highest_card_rank end end end # … end
  96. 122.

    Card = Struct.new(:rank, :suit) class Card::Rank TWO, THREE, FOUR, FIVE,

    SIX, SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING, ACE = 13.times.map { new } end class Card::Suit CLUBS, HEARTS, SPADES, DIAMONDS = 4.times.map { new } end three_of_diamonds = Card.new(Card::Rank::THREE, Card::Suit::DIAMONDS) queen_of_hearts = Card.new(Card::Rank::QUEEN, Card::Suit::HEARTS) ace_of_spades = Card.new(Card::Rank::ACE, Card::Suit::SPADES)
  97. 123.

    class Card::Rank include Comparable ORDER = ( TWO, THREE, FOUR,

    FIVE, SIX, SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING, ACE = 13.times.map { new } ) def <=>(other) ORDER.index(self) <=> ORDER.index(other) end end
  98. 124.

    class Hand::Category include Comparable ORDER = ( HIGH_CARD, ONE_PAIR, TWO_PAIR,

    THREE_OF_A_KIND, STRAIGHT, FLUSH, FULL_HOUSE, FOUR_OF_A_KIND, STRAIGHT_FLUSH = 9.times.map { new } ) def <=>(other) ORDER.index(self) <=> ORDER.index(other) end end
  99. 127.

    Hand::Rank = Struct.new(:hand) do include Comparable def category Hand::Category::ORDER. select

    { |category| category.matches?(hand) }.max end def <=>(other) if category == other.category category.compare(hand, other.hand) else category <=> other.category end end end
  100. 128.

    Hand = Struct.new(:cards) do def rank Hand::Rank.new(self) end end if

    my_hand.rank > your_hand.rank puts 'I win!' end
  101. 129.

    class Card::Rank ORDER = ( TWO, THREE, FOUR, FIVE, SIX,

    SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING, ACE = 13.times.map { new } ) def succ ORDER[ORDER.index(self).succ] end end
  102. 130.
  103. 131.
  104. 132.
  105. 133.

    class Card::Rank ORDER = ( TWO, THREE, FOUR, FIVE, SIX,

    SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING, ACE = 13.times.map { new } ) def succ ORDER[ORDER.index(self).succ % ORDER.size] end end
  106. 135.

    When a thing looks complicated, it’s possible that we’re looking

    at it wrong and missing some of the pieces of the puzzle.” — Richard Feynman “
  107. 136.