0eda45ef

ical-recurrence: express recurrence over a parameterised component

Groundwork for handling `RECURRENCE-ID`. **Nothing here is red**: this is a pure refactor. Every `.occ` and `.res` golden file is byte-identical, and the only new tests are `genValidSpec`s for the new types.

## Why the old entry points go away rather than gaining a fix

A component with a `RECURRENCE-ID` replaces the instance it names rather than adding an occurrence beside it, so the occurrences of one component depend on the other components sharing its UID. No function that takes a single component can be correct about that.

- `recur :: Day -> event -> R (Set event)` took one component and handed back a copy with a rewritten `DTSTART` and blanked recurrence properties — a component the calendar never contained.
- `recurEvents :: Day -> RecurringEvent -> R (Set EventOccurrence)` computed one component's own expansion under a name that claimed to compute a recurrence set. That expansion is still needed, so it survives as `expandRecurring`, which says what it does.

## VTODO and VJOURNAL

RFC 5545 gives `VEVENT`, `VTODO` and `VJOURNAL` the same recurrence properties, and §3.8.4.4 says `RECURRENCE-ID` identifies an instance of a "VEVENT, VTODO, or VJOURNAL". The only thing that differs is how the end of an instance is spelled: `DTEND`, `DUE`, and none respectively. `RecurrenceEnd` is that shared spelling, so a `VTODO`'s `DUE` is not typed as a `DTEND`, and `eventRecurring` / `todoRecurring` / `journalRecurring` are where the difference lives.

## The parameter

`Recurring`, `Occurrence` and `Resolved` are parameterised over the component so that one recurrence implementation serves all three, and so that a caller which has already narrowed a `VEVENT` down to what it cares about can still recur it. The `Functor` instances are how it swaps its own type in.

`HasRecurrence` is gone: a class over three known types buys nothing that three functions do not, and `makeOccurrence` existed only to hand back that never-contained component.

`ICal.Recurrence.Class` held the class, so it is renamed to `ICal.Recurrence.Types`, which is what it now holds.

Suite timing

Time to Start Worker time Duration Time to finish Idle
Config 0s 1s 1s 1s 0s
Eval 1s 10s 10s 11s 0s
Build 11s 1m08s 1m08s 1m19s 0s
Suite 0s 1m19s 1m19s 1m19s 0s

Timeline

0s10s20s30s40s50s1m1m10s