Skip to main content

Day 9 - Tests for tables

Skills: 1, 2

Pre-reading: 4.1.5, DRAFT:29.1

Intro (15 mins)

  • In the last few classes, we've shown table operations that take functions as arguments; some of those are complex, and benefit from being written with our full design process (e.g., calc-distance, or the function to obfuscate item names), but others, like subtract-1 seem a bit unnecessary. It would be nice if we could write:
    t = table: x-coord :: Number, y-coord :: Number
    row: 1, 2
    row: 3, 4
    end
    transform-column(t, "x-coord", n - 1)
  • But if we try to run this, we get an error -- n is not defined. What we want, instead of n, is a way of referring to the column value that is being transformed. When we defined a function, this is the argument:
    fun subtract-1(n :: Number) -> Number:
    doc: "subtracts 1 from input"
    n - 1
    where:
    subtract-1(10) is 9
    subtract-1(0) is -1
    subtract-1(-3.5) is -4.5
    end
  • For simple functions, we can do this with lam, which creates an unnamed function:
    transform-column(t, "x-coord", lam(n): n - 1 end)
  • Another oddity about the last few classes is that while we've followed our design process for helper functions, we haven't actually written functions that take tables and produce tables, and (for the most part), haven't written tests on tables.
  • For example, let's design a function that transforms a table, modifying a "price" column by discounting it by 20%, but only for prices that are below 100.
    fun apply-discounts(t :: Table) -> Table:
    doc: "transforms 'price' column by reducing 20%, if value is below 100"
    transform-column(t, "price", lam(price :: Number):
    if price < 100: price * 0.8 else: price end
    end)
    where:
    test-table =
    table: price
    row: 50
    row: 120
    row: 80
    row: 40
    end
    apply-discounts(test-table) is
    table: price
    row: 50 * 0.8
    row: 120
    row: 80 * 0.8
    row: 40 * 0.8
    end
    end
  • Note how we created an example table within our where: block, and in the test, rather than computing the actual numbers, wrote the expressions for the rows that should have changed. This makes it easier to understand the behavior.

Class Exercise (40 mins)

  • Design a function that takes a table that has a "price" column and adds a new column "tax", which is the sales tax rate where you are multiplied by the price. You can assume there is not already a tax column.
  • Create a function to carry out the "obfuscation" exercise from last class, and write tests for it. Note, your test tables should only need an "item" column!
  • Create a function to carry out the employee total earnings calculation from last time, and again write tests.

Wrap-up (5 mins)

  • lam allows us to more concisely use operations that expect functions as inputs, like transform-column, build-column, filter-with, order-by, etc.
  • Table functions should follow the same design process, and include tests, just like other functions!