The pipe function splits the computation into two concurrent parts, producer and consumer. The producer is
given a Sink to put values into, and consumer a Source to get those values from. Once producer and consumer
both complete, pipe returns their paired results.

Function get tries to get a value from the given Source argument. The intervening Pipe computations suspend
all the way to the pipe function invocation that created the source. The result of get is Nothing iff the
argument source is empty.

Function put tries to put a value into the given sink. The intervening Pipe computations suspend up to the
pipe invocation that has created the argument sink. The result of put indicates whether the operation succeded.