4c86abcf

ical-recurrence: express recurrence over a parameterised component

**1 of 4.** 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.

Sequence, each depending on the one before it: **this** → `recurrence-id` → `this-and-future` → `todo-and-journal`. I'll open the next once this is merged.

## 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.

---

Previously opened as #40 and merged by mistake without review; `master` has been put back to `cffbc57` and this is the same commit, unchanged.

Suite timing

Time to Start Worker time Duration Time to finish Idle
Config 1m05s 1s 1s 1m06s 1m05s
Eval 1m06s 10s 10s 1m17s 0s
Build 1m16s 0s 0s 1m16s 0s
Suite 1m05s 11s 11s 1m17s 1m05s

Timeline

0s1m10s