Class summary:   How Tables Evaluate
1 Summary of Table Operations So Far
2 Seeing When Table Functions are Evaluated

Class summary: How Tables Evaluate

Copyright (c) 2017 Kathi Fisler

We began with a brief review of the tables functions that we saw in the previous lecture.

  gradebook = table: name, SNC, exam1, exam2

    row: "Allie", false, 85, 90

    row: "Carl",  false, 75, 60

    row: "Elan", true, 95, 63

    row: "Lavon", false, 87, 88

    row: "Nunu", true, 70, 0

  end

We also introduced a new operation, build-column, which can be used to add a new column to a table. Here is an example of adding a column containing the average of the two exam grades:

  # add a column with the average of the exam grades

  fun exam-avg(r :: Row) -> Number:

    (r["exam1"] + r["exam2"]) / 2

  end

  

  build-column(gradebook, "avg", exam-avg)

Like filter-by, build-column takes a function as an input. This function computes the value that should be in the cell of the new column for the given row.

If you try out this code in the interactions window, then ask to see the gradebook again, the new "avg" column isn’t there. What happened? Table functions in Pyret do not modify the table they are operating over. They return a new table, leaving the old table intact. This is actually an extremely useful feature of programming, and we will explore this issue further in the coming lectures.

1 Summary of Table Operations So Far

As a summary, here are the functions we’ve been working with, summarized with their types (read :: as "has the type"). We show them here to reiterate that filter-by and build-column take functions as arguments, and that each of these functions takes a row as input.

  filter-by :: (t :: Table, (test :: Row->Boolean)) -> Table

  sort-by :: (t :: Table, col :: String, ascending :: Boolean) -> Table

  build-column :: (T :: Table, col :: String,

                   builder :: (Row -> Value)) -> Table

Why do the functions for building and filtering take entire rows, rather than just the columns we need? filter-by supports filters over any collection of columns. Pyret can’t guess which data a particular filtering might need, so it provides the entire row to all functions, leaving the functions to extract the data that they need and to ignore the rest.

2 Seeing When Table Functions are Evaluated

One common confusion with using functions like filter-by is understanding when the row-function (like taking-SNC) gets called. We write the row-functions in our file, but we don’t explicitly call them. So what calls these functions and when?

Internally, filter-by calls taking-SNC, once for each row. filter-by considers each row from top to bottom, passes it to taking-SNC, and creates a new table containing the rows for which taking-SNC returns true.

We also saw an initial demo of a new tool for Pyret that shows the sequence of function calls that get made when evaluating an expression. To use the tool, start Pyret from the following URL instead:

http://cpo.herokuapp.com/editor

Instead of a Run button, this version has a button marked "Trace and Run". Press this to run your program. If you want to trace a particular expression, evaluate it at the Interactions prompt, then hit "Trace Last". You’ll see a diagram of the function calls that got made while evaluating your expression. The function calls get made from left to right. If some function call in turn makes other calls, the circle for that call is a solid blue circle that you can expand. All of the expanded calls occur before the next "sibling" call. See the lecture capture (starting at minute 9) for details.

(Ignore the top-left dropdown for now – keep it on breadth-first, and we’ll come to the other options later)