Lab: Higher-order Functions

Dear Computer

Chapter 4: Functions

Lab: Higher-order Functions

In today's lab, you'll explore both sides of higher-order functions in Ruby. First you'll create your own higher-order function for processing a subset of elements in an array. Second you'll craft some calls to the map, filter, and fold functions in Ruby. Since Ruby doesn't technically have first-class functions, you'll use blocks to pass around code.

Take Through

Define in takethrough.rb a higher-order function in Ruby named take_through that collects up elements from an array until it encounters an element that meets some arbitrary criteria. It accepts an explicit array parameter and an implicit block parameter that returns true for the stopping element. It returns the subset of elements in a new array. Consider these example calls that demonstrate its behavior:

Ruby
# Take numbers until we hit 8.
p take_through([10, 9, 8, 7, 5]) { |x| x == 8 }
# [10, 9, 8]

# Take letters from the alphabet until we hit one in "dog".
p take_through(('a'..'z').to_a) { |c| "dog".include?(c) }
# ['a', 'b', 'c', 'd']

# Take numbers until we exceed 10.
sum = 0
p take_through((1..50).to_a) { |x|
  sum += x
  sum > 10
}
# [1, 2, 3, 4, 5]

Ensure these three calls produce the expected results, and add a call of your own.

Map, Filter, and Fold

In calls.rb, write short Ruby expressions that achieve the following tasks. Solve each with exactly one call to map, filter, or inject. In some cases, Ruby might provide convenience functions that solve the problem more succinctly than these three. Don't use them. Also don't use each, since its purpose is to achieve side-effects, not produce values.

You have a variable teams holding an array of arrays of player names, like [["Fern", "Wilbur", "Templeton"], ["Milo", "Addie", "Doc"]]. Produce an array of just the first players of these teams, like ["Fern", "Milo"].
You have an array of strings named files. Produce true if all the files exist, and false otherwise. Using all? is cheating.
You have an array of strings named tokens. Produce an array of just those strings whose first characters are the same as their last.
You have a string named message. Produce an array of its characters' decimal ASCII values.
You have an array of strings named entries. Produce true if at least one of the strings is nil, and false otherwise. Using any? is cheating.
You have an array of numbers representing magnitude triplets. For example, the array [49, 5, 13] represents 49 millions, 5 thousands, and 13 ones. Produce the full number. For example: 49005013.
You have an array of numbers named xs. Produce a parallel array of strings representing the signs of these numbers. Positive numbers are represented as '+', negative as '-', and zeroes as '0'.
You have two arrays of strings: names and bunglers. Produce an array of those names who are not bunglers.

Each solution should be an expression that evaluates to the described value. Verify that your solutions work by adding code that prints the produced values. For example, here's how we would test a map operation that produces an array of successors:

Ruby
xs = [1, 2, 3]
ys = xs.map { |x| x + 1 }
p ys

Do not print inside the blocks you pass to the higher-order functions.

Submit

To receive credit for this lab, you must submit your two Ruby scripts on Canvas by Monday noon. Late labs or forgot-to-submits are not accepted because Monday at noon is when your instructor has time to grade.

← Lecture: Higher-order Functions