At this point, you may be wondering "what's the point of treating functions as data? Isn't the point of functions to call them?". Enter call and run. These two blocks are the inverse of the gray border. They take a function, and evaluate it for us. The only difference between call and run is that call is for reporter blocks, and run is for command blocks.

Call takes in a function and inputs, and applies the function to those inputs. For example
call gray-border(_-_) with inputs 5 2
is equivalent to
5 - 2

We can even use call on variables and list items!

call function-as-data with inputs 5 2

call item 2 of list with inputs 5 2

Notice, however, that the inputs in these two call blocks do not have gray borders! This is because the two inputs already were "ringified" when they were set to a variable or added to a list. To get rid of the ring, you can right-click on the block and select "unringify."

As mentioned above, run works on command blocks. Example:
run gray-border(say _ for 2 seconds) with inputs Hello!

The example below is a homemade HOF! It takes in a function that draws some type of line, and uses that block to draw a tree.
block definition for draw tree with size, levels, line-type
We run it like this:
draw tree with 80, 3, simple line
or this:
draw tree with 80, 3, zig-zag
Try it out with the functions provided in the starter file, and then try making your own function that draws a different type of line. When making your own HOF blocks, you can get the gray-border input by clicking the input name in the block editor, then clicking the dropdown arrow. You'll be able to select "command" or "reporter" as the input type.

editing a function input name editing the details of a function's input name