Represent retry logic as transparent, easily testable policy objects

This branch allows code that wants to retry effects to represent this as a transparent policy object (with pretty minimal changes to the API of retrying). The way it's done is as follows:

- a new Effect intent, called "Retry", is added. It wraps the effect to retry and the retry policy (which is also just a callable).
- other things that were previously functions that closed over an environment have been replaced with classes with explicit attributes representing their data.
- should_retry_effect was dropped and now the users of this code should be using "retry_effect", in a way similar to the old way:

    ```new_eff = retry_effect(my_eff, retry_times(5), exponential_backoff_interval(2))```

To explain the change from function closures to objects-with-attributes:
- retry_times, which used to return a function closure, now returns an instance of a characteristic-based class RetryTimes (that is still a callable), which has a "max_retries" attribute (and "tries" to keep track of the state of how many times it's tried)
- exponential_backoff_interval has likewise been refactored into a characteristic-based ExponentialBackoffInterval class, with similar attributes.
- the inner function that used to be in should_retry_effect that invokes the can_retry function and the next_interval function and delays the retry has been factored into characteristic-based ShouldDelayAndRetry

This all comes together in that Retry.should_retry becomes a nice transparent tree of characteristic-based objects which expose all of their state and support equality. Now, unit tests just need to ensure that the policy looks sensible, instead of all the boilerplate involved with imperatively simulating errors in the code and ensuring that retry occurs the correct number of times and at the correct intervals.